有玩ctf的吗?用静态语言解这种题会不会很麻烦?
题目链接:http://167.71.246.232:8080/rabbit_hole.php23日前应该都有效,漏扫工具Nessus的开发商Tenable举办的,白皮能闲到设计这样的题还真少见,提示很少,就是题面的follow the rabbit hole,我是跑了好几遍程序调整好几次才想明白这玩意到底在弄啥。
点进去文本[]外面是下一个链接的尾巴,需要一路让程序点,一共有1582个。[]内则是一个文件按字节拆开转成16进制放在每个网页里,前面是这个字节在文件里的顺序号码,后面单引号里是字节内容,解题就是遍历所有网页,同时记录每个页面上的字节内容到一个list/数组,最后写成文件存到本地,打开这文件把记录的hex码贴到16进制编辑器新建的空白文件里(推荐hxd),发现是个png,另存打开,图上内容就是答案。
因为本人写代码就是业余时间玩玩,工作用不着,所以也挺久没碰静态语言了,一般就是写点脚本做做题,python和js都是毕业以后自学的。有点好奇像这种蛋疼的东西用静态语言解是不是会麻烦很多?有没有大拿给讲讲。
麻烦什么?
定义一个较大的字节数组,然后跟着后面的key遍历网页,把前面的内容按照不同的下标填到字节数组中,最后把字节数组写成文件 大约10-15分钟用Rust写了一个,答案是不麻烦,诀窍是使用现代的编程语言
use regex::Regex;
use std::{fs::File, io::Write};
const BASE: &str = "http://167.71.246.232:8080/rabbit_hole.php";
#
async fn main() {
let re =
Regex::new(r"(?i)\[(?P<loc>\d+),\s*'(?P<byte>{2})'\]\s*(?P<next>.+)").unwrap();
let mut next = BASE.to_string();
let mut data = Vec::new();
for count in 1.. {
let body = reqwest::get(&next).await.unwrap().text().await.unwrap();
match re.captures(&body) {
Some(cap) => {
data.push((
usize::from_str_radix(&cap["loc"], 10).unwrap(),
u8::from_str_radix(&cap["byte"], 16).unwrap(),
));
next = format!("{}?page={}", BASE, &cap["next"]);
}
None => {
break;
}
}
if count % 100 == 0 {
println!("block: {}", count);
}
}
data.sort_by_key(|&(loc, _)| loc);
let bytes: Vec<_> = data.into_iter().map(|(_, byte)| byte).collect();
let mut file = File::create("rabbit.png").unwrap();
file.write_all(&bytes).unwrap();
}
依赖有:
regex = "1.4.3"
reqwest = "0.11.0"
tokio = { version = "1.2.0", features = ["rt-multi-thread", "macros"] }
flag: automation_is_handy
麻烦点(最浪费代码量的地方)在于码字,能不能用第三方类库,大部分代码都浪费在于写http和正则。。。
和静态语言没啥关系,也许是c++标准库里没网络库给你带来的偏见 ctf很重要的一点就是效率,代码质量几乎没要求,当然是有大量库不需要重复造轮子的脚本语言优先
页:
[1]