嗯,不知不觉还是来到了这里,开始了Pwn的入门,就当做笔记用吧。
1.查壳
脱壳机 || 命令行1
upx -d filename --linux下
2.查看所使用的防护技术
接下来,我们可以用checksec脚本来查询该文件使用了哪些防护技术。1
checksec --file file
操作系统提供了许多安全机制来尝试降低或阻止缓冲区溢出攻击带来的安全风险,包括DEP、ASLR等。在编写漏洞利用代码的时候,需要特别注意目标进程是否开启了DEP(Linux下对应NX)、ASLR(Linux下对应PIE)等机制,例如存在DEP(NX)的话就不能直接执行栈上的数据,存在ASLR的话各个系统调用的地址就是随机化的。checksec脚本可以在这里下载。
Checksec:http://www.trapkit.de/tools/checksec.sh
Tubes读写接口:
对于一次攻击而言前提就是与目标服务器或者程序进行交互,这里就可以用remote(address,port)产生一个远程的socket然后就可以读写了。
>
conn = remote(‘ftp.debian.org’,21)
conn.recvline()
‘220 …’
conn.send(‘USER anonymous\r\n’)
conn.recvuntil(‘ ‘,drop = True)
‘331’
conn.recvline()
‘Please specify the password.\r\n’
conn.close()
同样的,使用process可以打开一个本地程序并进行交互
sh = process(‘/bin/sh’)
sh.sendline(‘sleep 3; echo hello world!;’)
sh.recvline(timeout=1)
‘’
sh.recvline(timeout=5)
‘hello world!\n’
sh.close
同时,也可以使用listen来开启一个本地的监听端口
l = listen()
r = remote(‘localhost’, l.lport)
c = l.wait_for_connection()
r.send(‘hello’)
c.recv()
‘hello’
无论哪种PIPE都是继承tube而来,可以用于读写函数主要有:
- interactive() : 直接进行交互,相当于回到shell的模式,在取得shell之后使用
- recv(numb = 4096,timeout = default):接收指定字节
- recvall() : 一直接收知道EOF
- recvline(keepends = True): 接收一行,keepends为是否保留行尾的\n,默认为Ture
- recvuntil((delims,drop=False):一直读到delims的pattern出现为止
- recvrepeat(timeout=default): 持续接收知道EOF或者timeout
- send(data) :发送数据
- sendline(data) : 发送一行数据,相当于在数据末尾加\n
下面是一些可用的函数:1
2
3
4
5
6
7
8
9asm(address, assembly) : 在指定地址进行汇编
bss(offset) : 返回bss段的位置,offset是偏移值
checksec() : 对elf进行一些安全保护检查,例如NX, PIE等。
disasm(address, n_bytes) : 在指定位置进行n_bytes个字节的反汇编
offset_to_vaddr(offset) : 将文件中的偏移offset转换成虚拟地址VMA
vaddr_to_offset(address) : 与上面的函数作用相反
read(address, count) : 在address(VMA)位置读取count个字节
write(address, data) : 在address(VMA)位置写入data
section(name) : dump出指定section的数据
ROP链生成器:
先简单回顾一下==ROP的原理==,由于NX开启不能在栈上执行shellcode,我们可以在栈上布置一系列的返回地址与参数,这样可以进行多次的函数调用,通过函数尾部的ret语句控制程序的流程,而用程序中的一些pop/ret的代码块(称之为gadget)来平衡堆栈。其完成的事情无非就是放上/bin/sh,覆盖程序中某个函数的GOT为system的,然后ret到那个函数的plt就可以触发system(‘/bin/sh’)。由于是利用ret指令的exploit,所以叫Return-Oriented Programming。(如果没有开启ASLR,可以直接使用ret2libc技术)
好,这样来看,这种技术的难点自然就是如何在栈上布置返回地址以及函数参数了。而ROP模块的作用,就是自动地寻找程序里的gadget,自动在栈上部署对应的参数。
常用函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22re = remote('ftp.debian.org',21) //远程连接
p = process('/bin/sh') //本地调试
send(data) : 发送数据
sendline(data) : 发送一行数据,相当于在末尾加\n
recvline() :接受一行数据
recvuntil((delims,drop=False):一直读到delims的pattern出现为止
recv(numb=4096, timeout=default) : 给出接收字节数,timeout指定超时
send(data) :发送数据
sendline(data) : 发送一行数据,相当于在数据末尾加\n
interactive() : 直接进行交互,相当于回到shell的模式,在取得shell之后使用
elf = ELF('./level2')
sys_add = elf.symbols["system"]
bin_add = elf.search("/bin/sh").next()
gdb filename --使用gdb开始调试
gdb中 disassemble function_name (反汇编某个函数)
pattern_create num 是生成一个字符串模板输入后根据EIP来确定覆盖return addr的长度。
pattern_offset address 查询偏移量
对于整数的pack与数据的unpack,可以使用p32,p64,u32,u64这些函数,分别对应着32位和64位的整数。(主要是对整数进行打包,就是转换成二进制的形式,比如转换成地址。p32、p64是打包,u32、u64是解包。)
ROPgadget命令:1
ROPgadget--binary level2_x64 --only "pop|ret"|grep rdi
by Covteam-Sma11_Tim3
生活不易,多才多艺。