https://github.com/eternalsakura/ctf_pwn/blob/master/pragyan2018/police_academy
程序举例
输出结果 AA简单调试 编译程序
可以看出函数里本来应该只对a赋值。
但是b的值也被覆盖为A了,这里其实就可以栈溢出,但是在本题中只需要覆盖栈内变量即可。
64位程序,canary,NX保护
密码被硬编码进程序,即kaiokenx20
这个函数的作用就是根据文件名读取文件,这个文件名本来是根据我们的选项(1-7)来决定的,比如如果是7,则v8 = 'txt.galf'。 但是可以看出,如果我们输入的数在1-7之外,那么就不会对v8赋值,如果我们通过前面的scanf直接把v8的值覆盖成我们想要读取的文件名(flag.txt),那么就可以读取到flag了。
因为我们提供的v8的文件名要等于36字节,但是flag.txt没有那么长,所以这里,我们可以用./././..来填充。
首先用scanf覆盖是s1的值为密码(kaiokenx20)+padding,覆盖v8的值为././././././././././././././flag.txt,然后读取flag。
s1需填充0x10即16个字节,v8填充36个字节。
https://github.com/eternalsakura/ctf_pwn/tree/master/pragyan2018/unbreakable_encryption
pwn题中,有形如下述代码的形式就是格式化字符串漏洞
也许使用者的目的只是直接输出字符串,但是这段字符串来源于可控的输入,就造成了漏洞。 示例程序如下
编译:gcc -m32 -o str str.c
输入:%2$x
原因是如果直接printf(“占位符”)这种形式,就会把栈上的偏移当做数据输出出来。通过构造格式化串,就可以实现任意地址读和任意地址写。
事实上,我们在scanf(或者read)来输入字符串的时候,字符串就已经在栈中了,如图,可以看出偏移为6。如果我们构造出addr(4字节)%6$s
,就能读取这个地址的值了。 我们尝试一下,输入AAAA%6$s
,当然不可能真的读到地址为41414141的内存值,不过从下图我框起来的内容就知道,如果我们输入一个合法的值,就可以读了。
和上面的任意地址读是同理的,只不过利用了格式化字符串的一个比较冷门的特性,%n。 这个占位符可以把它前面输出的字符的数量,写入指定的地址。 比如
val的值就被改变为3。
下述示例来源于RE4B。
linux上优先使用RDI,RSI,RDX,RCX,R8,R9寄存器传递前6个参数,然后利用栈传递其余参数。 汇编代码如下
所以有
所以在64位格式化字符串漏洞利用时,要注意如何计算偏移,因为即使没有占位符,我们依然是按照这个传参规则来读取变量的。
http://pwntools.readthedocs.io/en/stable/fmtstr.html 上面说过我们要利用格式化串漏洞就要得到格式化串的偏移,pwntools有自动化代码可以得到这个偏移。
生成任意地址写的payload的函数.
fmtstr_payload有两个参数
读取输入并打印,并将其传递给encrypt,加载aes文件,加密消息并将其输出到屏幕。 然后它调用decrypt解密,并将明文输出到屏幕上。
scanf处存在栈溢出,上一个题的前置知识已经说过了。 不过这个题因为有canary,所以不能用来直接getshell,我们要想其他方法。
因为静态链接,所以不能改写GOT表,考虑使用malloc_hook来解题,可以参考0ctf的easiestprintf。 其次因为有canary,所以要先leak出canary。 所以总的思路就出来了:
参数a1应该为_libc_stack_end的地址了。_stack_prot通过rop修改为0x7即111b,这样的话stack就是可执行的了,然后就可以执行shellcode了。 直接search。
main
pop_eax
pop_eax = 0x0804c906
jmp_esp = 0x08174bec
要确定偏移需要多次调试,没有什么好的方法。 这里我也是把已经调试好的偏移直接带入跟了一遍而已。 要在pwntools里用gdb调试,首先要先设置好断点文件,然后gdb.attach(r,open(filename)) 得到断点文件的方法如下。
然后执行程序
printf执行完后,malloc_hook等于main函数的首地址。
跳回main函数,为了确定跳回,先在main下个断点
继续执行,断在printf
注意hhn代表只覆盖单字节。 这次printf结束之后,__stack_prot的值被修改为7。
继续c还会再跳回main函数,因为malloc_hook还指向main函数。
继续c,执行到printf,这次我不再步入printf里,所以esp就指向格式化串。
printf执行完成后,malloc_hook已经恢复为0,不再会跳回main了,另外可以看出我们的leak出的canary和shellcode已经写入了栈里,实现了栈溢出。
当main函数执行结束,要ret的时候,就返回到我们布置好的利用链里。
栈可执行打开,并跳入shellcode执行。
解密AES得到flag为pctf{th4t_m0m3n1-wh3n~f0rm41`SpiLls_0v3r}
https://github.com/phieulang1993/ctf-writeups/blob/master/2018/pragyan/aes_enc_unbf/aes_enc_unbf.py
Chris is trying out to be a police officer and the applications have just been sent into the police academy.
He is really eager to find out about his competition.
Help it him back the system and view the other applicant’s applications.
The service is running at 128.199.224.175:13000
Hint! Path Traversals are always a classic.
#include <stdio.h>
int main(void){
char a,b;
printf("input character a,b\n");
scanf("%s",&a);//bug
printf("%c%c\n",a,b);
return 0;
}
gcc test.c -g -o test
sakura@ubuntu:~$ gdb test
Loaded 112 commands. Type pwndbg [filter] for a list.
Reading symbols from test...done.
pwndbg> b 5
Breakpoint 1 at 0x4005ff: file test.c, line 5.
pwndbg> r
Starting program: /home/sakura/test
input character a,b
...
pwndbg> n
AAAA
6 printf("%c%c\n",a,b);
...
pwndbg> p a
$1 = 65 'A'
pwndbg> p b
$2 = 65 'A'
pwndbg> c
Continuing.
AA
scanf("%s",&a)
sakura@ubuntu:~$ checksec police_academy
[*] '/home/sakura/police_academy'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
sakura@ubuntu:~$
if ( strncmp(&s1, "kaiokenx20", 10uLL) )
__int64 v8; // [rsp+20h] [rbp-30h]
...
v6 = print_record((const char *)&v8);
signed __int64 __fastcall print_record(const char *a1)
{
FILE *stream; // [rsp+18h] [rbp-338h]
char ptr; // [rsp+20h] [rbp-330h]
unsigned __int64 v4; // [rsp+348h] [rbp-8h]
v4 = __readfsqword(0x28u);
if ( (unsigned int)strlen(a1) != 36 ) // 文件名要等于36字节
return 0xFFFFFFFFLL;
stream = fopen(a1, "r");
if ( !stream )
return 0xFFFFFFFFLL;
printf("\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "r");
puts("\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
fread(&ptr, 0x30CuLL, 1uLL, stream);
printf("%s", &ptr);
printf("\n\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
printf("\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
fclose(stream);
return 0LL;
}
__isoc99_scanf("%d", &v5);
switch ( v5 )
{
case 1:
v8 = 3474298655558951218LL;
v9 = 3847821640488804656LL;
v10 = 7149858464072819505LL;
v11 = 7221017546570621237LL;
v12 = 1952539694;
v13 = 0;
break;
case 2:
v8 = 7147605565415700579LL;
v9 = 3631416849257871156LL;
v10 = 4121973650644951905LL;
v3 = (int *)4049125503535429937LL;
v11 = 4049125503535429937LL;
v12 = 1952539694;
v13 = 0;
break;
case 3:
v8 = 0x3233613163393238LL;
v9 = 3702634411308757558LL;
v3 = (int *)7076898166606619443LL;
v10 = 7076898166606619443LL;
v11 = 7219893850032333154LL;
v12 = 1952539694;
v13 = 0;
break;
case 4:
v8 = 7221577417837786465LL;
v3 = (int *)7363447393777498210LL;
v9 = 7363447393777498210LL;
v10 = 7017788206782754871LL;
v11 = '06491899';
v12 = 'tad.';
v13 = 0;
break;
case 5:
v8 = 'cb7eb354';
v9 = 7147275711155430960LL;
v10 = 7076672766706148656LL;
v3 = (int *)3486685753473249589LL;
v11 = 3486685753473249589LL;
v12 = 1952539694;
v13 = 0;
break;
case 6:
v8 = 0331433146246314630463LL;
v9 = 'b5d57a29';
v3 = (int *)'a7e6a65d';
v10 = 'a7e6a65d';
v11 = 'c721627f';
v12 = 'tad.';
v13 = 0;
break;
case 7:
v8 = 'txt.galf';
LOBYTE(v9) = 0;
puts("You don't have the required privileges to view the flag, yet.");
exit(0);
return result;
default:
break;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2018-3-7 08:49
被sakura零编辑
,原因: