Skip to content

Instantly share code, notes, and snippets.

@h4x5p4c3
Last active January 25, 2023 18:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save h4x5p4c3/da447b85a59a5defa4b5747d949f0a03 to your computer and use it in GitHub Desktop.
Save h4x5p4c3/da447b85a59a5defa4b5747d949f0a03 to your computer and use it in GitHub Desktop.
solve script for QilingLab x86_64
#!/usr/bin/env python3
# https://www.shielder.it/blog/2021/07/qilinglab-release/
from qiling import Qiling
from qiling.const import QL_VERBOSE
from qiling.os.mapper import QlFsMappedObject
import struct
def u8(inp):
return struct.unpack("<Q", inp)
def level1(ql):
ql.mem.map(0x1000, 0x1000) #hex(0x1337//4096*4096)
ql.mem.write(0x1337, ql.pack16(1337))
def ql_syscall_uname(ql, address, *args, **kw):
buf = b'QilingOS'.ljust(65, b'\x00')
buf += b'ql_vm'.ljust(65, b'\x00')
buf += b'99.0-RELEASE'.ljust(65, b'\x00')
buf += b'ChallengeStart'.ljust(65, b'\x00')
buf += b'ql_processor'.ljust(65, b'\x00')
buf += b''.ljust(65, b'\x00')
ql.mem.write(address, buf)
regreturn = 0
return regreturn
def level2(ql):
ql.set_syscall("uname", ql_syscall_uname)
#https://hackmd.io/@ziqiaokong/BkbGuCJND
class Fake_urandom(QlFsMappedObject):
def read(self, size):
if size == 1:
return b"\xff"
else:
return b"\x00" * size
def fstat(self): # syscall fstat will ignore it if return -1
return -1
def close(self):
return 0
#ssize_t getrandom(void *buf, size_t buflen, unsigned int flags);
def ql_syscall_getrandom(ql, buf, buflen, flags,*args, **kw):
regreturn = None
try:
ql.mem.write(buf, b"\x00" * buflen)
regreturn = len(data)
except:
regreturn = -1
def level3(ql):
ql.add_fs_mapper("/dev/urandom", Fake_urandom())
ql.set_syscall("getrandom", ql_syscall_getrandom)
''' level4
0x00000e40 mov eax, dword [var_8h]
0x00000e43 cmp dword [var_4h], eax
'''
def level4_sol(ql):
ql.mem.write((ql.reg.rax), b'\x01')
def level4(ql):
ql.hook_address(level4_sol, ql.base+0x154e40)
def level5(ql):
ql.reg.rax = 0
ql.set_api('rand', level5)
def level6(ql):
ql.patch(ql.base + 0xf18, b"\x74")
def loop(ql):
ql.reg.al = 0 #test al,al
def level6(ql):
ql.hook_address(loop, ql.base+0x154f16)
def level7(ql):
ql.set_api('sleep', lambda seconds: 0)
def write_target(ql):
addr = ql.mem.read(ql.reg.rax, 0x18)
ql.mem.write(u8(addr[0x10:])[0], b'\x01')
def level8(ql):
ql.hook_address(write_target, ql.base+0x154fb5)
def level9(ql):
ql.reg.rax = ql.reg.rdi
ql.set_api("tolower", level9)
class Fake_cmdline(QlFsMappedObject):
def read(self, size):
return b"qilinglab" # fixed value for reading
def fstat(self): # syscall fstat will ignore it if return -1
return -1
def close(self):
return 0
def level10(ql):
ql.add_fs_mapper("/proc/self/cmdline", Fake_cmdline())
'''
mov DWORD PTR [rbp-0x30],esi
mov DWORD PTR [rbp-0x34],ecx
mov DWORD PTR [rbp-0x2c],eax
'''
def cpuid(ql):
ql.reg.rsi = 0x696C6951
ql.reg.rcx = 0x614C676E
ql.reg.rax = 0x20202062
def level11(ql):
ql.hook_address(cpuid, ql.base+0x155195)
def solve(path, rootfs, verbose):
ql = Qiling(path, rootfs, verbose=verbose)
ql.base = 0x555555400000
level1(ql)
level2(ql)
level3(ql)
level4(ql)
level5(ql)
level6(ql)
level7(ql)
level8(ql)
level9(ql)
level10(ql)
level11(ql)
ql.run()
if __name__ == "__main__":
solve(["x86_64/qilinglab-x86_64"], "rootfs/x8664_linux", QL_VERBOSE.OFF)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment