Solve me writeup
warmup
题目链接:http://warmup.solveme.peng.kr/
签到题,打开上面有一个base64加密的值,根据下面的代码,还原出flag。


Thirty six
题目描述:
The length of alphanumeric is thirty six.
`59714216653669596140166323768414581512983971077273551022216`
看了别人的wp才知道是转成36进制,misc题套路知道的还是太少。
一开始拿这串数字在线转换进制,但是得到的flag错了,自己写的脚本算出的居然也是和在线网站算的一样,思考了一会才发现原来python在大整数/除运算时已经会出现偏差,

所以要得到真正的除并且取整,用//这个符号运算即可。下面贴出代码
s = "0123456789abcdefghijklmnopqrstuvwxyz"
n = 59714216653669596140166323768414581512983971077273551022216
m = []
while True:
t =n//36
m.append(n%36)
n = t
if n==0:
break
m.reverse()
ans = ''
for i in m:
ans += s[i]
print(ans)
Badcompare
题目链接:http://badcompare.solveme.peng.kr
代码审计
<?php
error_reporting(0);
require __DIR__.'/lib.php';
if(isset($_GET['answer'])){
if($_GET['answer'] === '尊찢悼嚴隆'){
echo $flag;
}else{
echo 'Wrong answer';
}
echo '<hr>';
}
highlight_file(__FILE__);
可以看到是只要输入answer等于后面那串字符就能拿到flag,但是直接复制肯定是不行的,浏览器已经帮你渲染了。我们把文件下载下来,然后在16进制编辑器打开复制16进制流
F0EEC2F5D3FAE5F1D7CC
然后在前面加%转换成urlencode形式访问拿到flag

Winter sleep
题目链接:http://wintersleep.solveme.peng.kr/
代码审计
<?php
error_reporting(0);
require __DIR__.'/lib.php';
if(isset($_GET['time'])){
if(!is_numeric($_GET['time'])){
echo 'The time must be number.';
}else if($_GET['time'] < 60 * 60 * 24 * 30 * 2){
echo 'This time is too short.';
}else if($_GET['time'] > 60 * 60 * 24 * 30 * 3){
echo 'This time is too long.';
}else{
sleep((int)$_GET['time']);
echo $flag;
}
echo '<hr>';
}
highlight_file(__FILE__);
前面直接比大小,最后面在echo $flag之前还sleep了一下,我们的目标就是让前面都通过(保证数字有那么大),还得sleep足够小。
首先is_numeric()函数是允许科学计数法的,而int是不允许科学计数法表示的。所以当int强制转换时就会将其当做第一个字母前面的数字转换,而且如果为小数会强制转换成0,如果为0.8e9(即0.8×10^9)也会被int强制转换成0。那么我们现在只要找到一个合适的科学计数法的数满足上面的条件就行了。

Hard Login
题目链接:http://hardlogin.solveme.peng.kr/login.php
<?php
error_reporting(0);
session_start();
require __DIR__.'/lib.php';
if(isset($_GET['username'], $_GET['password'])){
if(isset($_SESSION['hard_login_check'])){
echo 'Already logged in..';
}else if(!isset($_GET['username']{3}) || strtolower($_GET['username']) != $hidden_username){
echo 'Wrong username..';
}else if(!isset($_GET['password']{7}) || $_GET['password'] != $hidden_password){
echo 'Wrong password..';
}else{
$_SESSION['hard_login_check'] = true;
echo 'Login success!';
header('Location: ./');
}
echo '<hr>';
}
highlight_file(__FILE__);
看上去这道题好像是通过某种方式绕过,其实看代码如果真的成功登陆了也只是跳转到/主页,说明flag很可能就是在/主页中,然而我们访问http://hardlogin.solveme.peng.kr/时,会被浏览器302跳转到login,所以我们用 curl访问,curl不会跟随302跳转获取到主页内容,其中就包含了flag。

URL filtering
题目链接:http://urlfiltering.solveme.peng.kr
<?php
error_reporting(0);
require __DIR__."/lib.php";
$url = urldecode($_SERVER['REQUEST_URI']);
$url_query = parse_url($url, PHP_URL_QUERY);
$params = explode("&", $url_query);
foreach($params as $param){
$idx_equal = strpos($param, "=");
if($idx_equal === false){
$key = $param;
$value = "";
}else{
$key = substr($param, 0, $idx_equal);
$value = substr($param, $idx_equal + 1);
}
if(strpos($key, "do_you_want_flag") !== false || strpos($value, "yes") !== false){
die("no hack");
}
}
if(isset($_GET['do_you_want_flag']) && $_GET['do_you_want_flag'] == "yes"){
die($flag);
}
highlight_file(__FILE__);
问题在于怎么bypass,这里就得说parse_url这个bug多多的函数了,更多关于parse_url在这篇文章中讲得很清楚,在这里我们只讲述与本题相关的。当传入参数为以下时
http://urlfiltering.solveme.peng.kr///?do_you_want_flag=yes
parse_url()函数会返回false,相当于没有解析出参数来,那就直接bypass了

Hash collision
题目链接:http://hashcollision.solveme.peng.kr/
<?php
error_reporting(0);
require __DIR__.'/lib.php';
if(isset($_GET['foo'], $_GET['bar'])){
if(strlen($_GET['foo']) > 30 || strlen($_GET['bar']) > 30){
die('Too long');
}
if($_GET['foo'] === $_GET['bar']){
die('Same value');
}
if(hash('sha512', $_GET['foo']) !== hash('sha512', $_GET['bar'])){
die('Different hash');
}
echo $flag, '<hr>';
}
highlight_file(__FILE__);
php中的hash函数和md5函数是一样的,输入列表的话会直接返回false,所以如果两个值都为列表,那么就绕过了。

Array2String
题目链接:http://array2string.solveme.peng.kr/
<?php
error_reporting(0);
require __DIR__.'/lib.php';
$value = $_GET['value'];
$username = $_GET['username'];
$password = $_GET['password'];
for ($i = 0; $i < count($value); ++$i) {
if ($_GET['username']) unset($username);
if ($value[$i] > 32 && $value[$i] < 127) unset($value);
else $username .= chr($value[$i]);
if ($username == '15th_HackingCamp' && md5($password) == md5(file_get_contents('./secret.passwd'))) {
echo 'Hello '.$username.'!', '<br>', PHP_EOL;
echo $flag, '<hr>';
}
}
highlight_file(__FILE__);
看for循环里,我们需要把$username变成15th_HackingCamp
$password变成./secret.passwd文件里的内容,password很简单我们直接访问http://array2string.solveme.peng.kr/secret.passwd就能拿到password。
if ($_GET['username']) unset($username);
if ($value[$i] > 32 && $value[$i] < 127) unset($value);
else $username .= chr($value[$i]);
$username我们只能一个字母一个字母的拼凑,所以value的值我们需要输入一个列表进去。但是,它不允许value其中的值在32到127之间,那么这样已经不允许输入ascii可打印字符了。不过,chr函数有一个特性就是它会将其中参数模256后再进行转化。这意味着,如果输入chr(97+256),它也会返回‘a'.
于是我们可以构造以下url获得flag:http://array2string.solveme.peng.kr/?value[]=305&value[]=309&value[]=372&value[]=360&value[]=351&value[]=328&value[]=353&value[]=355&value[]=363&value[]=361&value[]=366&value[]=359&value[]=323&value[]=353&value[]=365&value[]=368&password=simple_passw0rd

Flag not found
题目链接:http://flagnotfound.solveme.peng.kr/
把文件下下来,binwalk走一下。

google了一下lh7文件,是一种不常用的压缩格式,后缀为.lzh 但是自带的解压软件应该是能解开的。
根据binwalk,用16进制编辑器将62字节以后的数据复制转储为另一个文件,将这个文件后缀改为.lzh ,打开有一个flag.txt,看看有啥

??? 黑人问号脸。。。 做到这我就做不下去了,感觉到这应该就可以了,google也没找到writeup,先放着吧。
Give me a link
题目链接:http://givemealink.solveme.peng.kr/
从代码可以看到在重重限制过后,会向构造好的域名发送flag,那么我们的目标就是突破限制将最后访问的url构造成我们自己的域名或者ip,然后从访问记录中拿到flag。
我们可以看到,三个限制就是三个if语句,第一个限制过滤了_、不可见字符(等价于[ \f\n\r\t\v])和空字符。第二个要求我们输入的url应该是以http://givemealink.solveme.peng.kr/开头,第三个要求域名后面的地址应该为/plz_give_me
显然第一个限制和第三个矛盾,而我们也得绕过第二个限制才能填上我们自己的域名。
我们先看看怎么绕过第一个和第三个之间的矛盾,parse_url