Qiling Lab Writeup

- 4 mins

So this was a long term plan as i wanted to learn about emulation and moreover qiling as this framework has so much capability as of it having less documention less people know about it but two days prior i found out a challenge named QilingLab – Release by @TheZero and @ShielderSec as of for now i solved 9/11 challenges for now 2 are left but would be done in the next update.

Here’s the script:

from qiling import *
from qiling.const import *
from capstone import *
import logging
from qiling.os.mapper import QlFsMappedObject


class Fake_urandom(QlFsMappedObject):

    def read(self, size):
    	if size == 1:
    		return b"\xFF"
    	return b"\x00" * size # fixed value for reading /dev/urandom
    def fstat(self): 
        return -1# syscall fstat will ignore it if return -1

    def close(self):
        return 0

class Fake_cmdline(QlFsMappedObject):

	def read(self,size):
		return b"qilinglab" # fixed value for reading /dev/urandom

	def fstat(self):
		return -1 # syscall fstat will ignore it if return -1
	def close(self):
		return 0

def getrandom_onexit(ql, buf, buflen, flags,*args, **kw):
    data = None
    regreturn = None
    try:
        data = b"\x00" * buflen
        ql.mem.write(buf, data)
        regreturn = len(data)
    except:
        regreturn = -1

    if data:
        ql.log.debug("getrandom() CONTENT:")
        ql.log.debug(str(data))
    return regreturn

def uname_onexit(ql,address ,arg1, arg2, arg3, *args):
    print("exiting uname syscall and changing values accordingly!")
    buf = b''
    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 solve_chall1(q1):
	q1.mem.map(0x1000,0x1000)
	q1.mem.write(0x1337,q1.pack16(1337))

def solve_chall3(q1):
	q1.reg.eax = 1

def solve_chall5(q1):
	q1.reg.eax = 0

def solve_chall6(q1):
	q1.reg.al = 0
def solve_chall7(q1):
	q1.reg.edi = 0
def solve_chall9(q1):
	q1.reg.rdx = q1.reg.rax

if __name__ == '__main__':
	q1 = Qiling(["qilinglab-x86_64"], "x8664_linux")
	q1.mem.show_mapinfo()
	solve_chall1(q1) #challenge 1
	q1.set_syscall(63, uname_onexit) #challenge 2
	q1.add_fs_mapper("/dev/urandom", Fake_urandom())
	q1.set_syscall(318, getrandom_onexit)
	q1.hook_address(solve_chall3, 0x555555554e43)
	q1.hook_address(solve_chall5, 0x555555554e92)
	q1.hook_address(solve_chall6, 0x555555554f16)
	q1.hook_address(solve_chall7, 0x555555554f3c)
	q1.hook_address(solve_chall9, 0x55555555504b)
	q1.add_fs_mapper("/proc/self/cmdline", Fake_cmdline())
#two challenges still unsolved chall 8 chall 11
	q1.run()

At some points I changed the registers by just putting the hook at the address rather than changing the function and it will be cleared by the next update.

Thank you so much @TheZero and @ShielderSec for these challenges : )

comments powered by Disqus
rss facebook twitter github mail instagram linkedin