QilingLab challenge writeup

Overview

qiling lab writeup

shielder 在 2021/7/21 發布了 QilingLab 來幫助學習 qiling framwork 的用法,剛好最近有用到,順手解了一下並寫了一下 writeup。

前情提要

Qiling 是一款功能強大的模擬框架,和 qemu user mode 類似,但可以做到更多功能,詳情請見他們的 github網站

他們有官方文件,解此題目前建議看一下。

我所解的為 aarch64 的 challenge,使用的 rootfs 為 qililng 所提供的 arm64_linux

逆向工具用 ghidra,因為我沒錢買 idapro。

First

先隨手寫個 python 用 qiling 執行 challenge binary。

import sys
from qiling import *
from qiling.const import QL_VERBOSE

sys.path.append("..")


if __name__ == "__main__":
    ql = Qiling(["qilinglab-aarch64"], "rootfs/arm64_linux",verbose=QL_VERBOSE.OFF)
    ql.run()

可以看到結果是 binary 會不正常執行,此為正常現象,有些 Challenge 沒解完會導致錯誤或是無窮迴圈。

Welcome to QilingLab.
Here is the list of challenges:
Challenge 1: Store 1337 at pointer 0x1337.
Challenge 2: Make the 'uname' syscall return the correct values.
Challenge 3: Make '/dev/urandom' and 'getrandom' "collide".
Challenge 4: Enter inside the "forbidden" loop.
Challenge 5: Guess every call to rand().
Challenge 6: Avoid the infinite loop.
Challenge 7: Don't waste time waiting for 'sleep'.
Challenge 8: Unpack the struct and write at the target address.
Challenge 9: Fix some string operation to make the iMpOsSiBlE come true.
Challenge 10: Fake the 'cmdline' line file to return the right content.
Challenge 11: Bypass CPUID/MIDR_EL1 checks.

Checking which challenge are solved...
Note: Some challenges will results in segfaults and infinite loops if they aren't solved.
[x]	

[x]	x0	:	 0x0
[x]	x1	:	 0x0
[x]	x2	:	 0x1
[x]	x3	:	 0x0
[x]	x4	:	 0x0

Challenge 1

把 0x1337 的位置的值改成 1337

用 qiling 把該位置的 memory 讀出來,在進行改寫,要注意 align 問題。詳情請見文件

    ql.mem.map(0x1337//4096*4096, 4096)
    ql.mem.write(0x1337,ql.pack16(1337) )

Challenge 2

改掉 uname 此 system call 的 return。

可以看到他去比對 uname.sysname 和 uname.version 是否為特定值。我採用對 system call 進行 hijack

去翻 linux 文件 可以看到 uname 回傳的格式為 :

struct utsname {
               char sysname[];    /* Operating system name (e.g., "Linux") */
               char nodename[];   /* Name within "some implementation-defined
                                     network" */
               char release[];    /* Operating system release
                                     (e.g., "2.6.28") */
               char version[];    /* Operating system version */
               char machine[];    /* Hardware identifier */
           #ifdef _GNU_SOURCE
               char domainname[]; /* NIS or YP domain name */
           #endif
};

依照此文件把相對應的位置改掉。注意如果 release 改太小或是沒給,會噴錯。

def my_syscall_uname(ql, write_buf, *args, **kw):
    buf = b'QilingOS\x00' # sysname
    ql.mem.write(write_buf, buf)
    buf = b'30000'.ljust(65, b'\x00') # important!! If not sat will `FATAL: kernel too old`
    ql.mem.write(write_buf+65*2, buf)
    buf = b'ChallengeStart'.ljust(65, b'\x00') # version
    ql.mem.write(write_buf+65*3, buf)
    regreturn = 0
    return regreturn

ql.set_syscall("uname", my_syscall_uname)

Challenge 3

/dev/random,從中讀取兩次,確保第一次的值和 getrandom 得到的值相同,且其中沒有第二次讀到值。

查了一下 getrandom 是一 system call。因此對 /dev/random 和 getrandom() 進行 hijack 即可

class Fake_urandom(QlFsMappedObject):
    def read(self, size):
        if(size > 1):
            return b"\x01" * size
        else:
            return b"\x02"
    def fstat(self): # syscall fstat will ignore it if return -1
        return -1
    def close(self):
        return 0

def my_syscall_getrandom(ql, write_buf, write_buf_size, flag , *args, **kw):
    buf = b"\x01" * write_buf_size
    ql.mem.write(write_buf, buf)
    regreturn = 0
    return regreturn
    
ql.add_fs_mapper('/dev/urandom', Fake_urandom())
ql.set_syscall("getrandom", my_syscall_getrandom)

Challenge 4

進入不能進去的迴圈

直接 hook cmp 的位置讓 reg w0 是 1 即可,位置記得要加上 pie。

    # 00100fd8 e0 1b 40 b9     ldr        w0,[sp, #local_8]
    # 00100fdc e1 1f 40 b9     ldr        w1,[sp, #local_4]
    # 00100fe0 3f 00 00 6b     cmp        w1,w0    <- hook         
def hook_cmp(ql):
    ql.reg.w0 = 1
    return

base_addr = ql.mem.get_lib_base(ql.path) # get pie_base addr
ql.hook_address(hook_cmp, base_addr + 0xfe0)

Challenge 5

rand() 出來的值和 0 比較要通過

直接 hijack rand() 讓他回傳都是 0 即可。

def hook_cmp(ql):
    ql.reg.w0 = 1
    return
    
ql.set_api("rand", hook_rand)

Challenge 6

解開無窮迴圈

和 Challenge 4 同想法,hook cmp。

def hook_cmp2(ql):
    ql.reg.w0 = 0
    return
    
ql.hook_address(hook_cmp2, base_addr + 0x001118)

Challenge 7

不要讓他 sleep。 解法很多,可以 hook sleep 這個 api,或是看 sleep linux 文件能知道內部處理是用 nanosleep,hook 他即可。

def hook_sleeptime(ql):
    ql.reg.w0 = 0
    return
ql.hook_address(hook_sleeptime, base_addr + 0x1154)

Challenge 8

裡面最難的一題,他是建立特殊一個結構長這個樣子。

struct something(0x18){ 
 string_ptr -> malloc (0x1e) ->  0x64206d6f646e6152
 long_int = 0x3DFCD6EA00000539
 check_addr -> check;
}  

由於他結構內部有 0x3DFCD6EA00000539 這個 magic byte,因此可以直接對此作搜尋並改寫內部記憶體。這邊要注意搜尋可能找到其他位置,因此前面可以加對 string_ptr 所在位置的判斷。

def find_and_patch(ql, *args, **kw):
    MAGIC = 0x3DFCD6EA00000539
    magic_addrs = ql.mem.search(ql.pack64(MAGIC)) 

    # check_all_magic
    for magic_addr in magic_addrs:
        # Dump and unpack the candidate structure
        malloc1_addr = magic_addr - 8
        malloc1_data = ql.mem.read(malloc1_addr, 24)
        # unpack three unsigned long
        string_addr, _ , check_addr = struct.unpack('QQQ', malloc1_data)

        # check string data        
        if ql.mem.string(string_addr) == "Random data":
            ql.mem.write(check_addr, b"\x01")
            break
    return
    
ql.hook_address(find_and_patch, base_addr + 0x011dc)

另一種解法則是由於該結構在 stack 上,因此直接讀 stack 即可。

Challenge 9

把一字串轉用tolower小寫,再用 strcmp 比較。

解法一樣很多種,我是 hijack tolower() 讓他啥事都不做。

def hook_tolower(ql):
    return
    
ql.set_api("tolower", hook_tolower)

Challenge 10

打開不存在的文件,讀取的值需要是 qilinglab

和 Challenge 3 作法一樣,這邊要注意的是 return 要是 byte,string 會出錯。 = =

class Fake_cmdline(QlFsMappedObject):

    def read(self, size):
        return b"qilinglab" # type should byte byte, string will error = =
    def fstat(self): # syscall fstat will ignore it if return -1
        return -1
    def close(self):
        return 0

ql.add_fs_mapper('/proc/self/cmdline', Fake_cmdline())

Challenge 11

可以看到他從 MIDR_EL1 取值,而此為特殊的暫存器。

這邊解法是去 hook code,我選擇 hook 這段

# 001013ec 00 00 38 d5     mrs        x0,midr_el1

去搜尋所有記憶體為 b"\x00\x00\x38\xD5" ,讓他執行時把 x0 暫存器改寫,並更改 pc。

def midr_el1_hook(ql, address, size):  
    if ql.mem.read(address, size) == b"\x00\x00\x38\xD5":
        # if any code is mrs        x0,midr_el1
        # Write the expected value to x0
        ql.reg.x0 = 0x1337 << 0x10
        # Go to next instruction
        ql.reg.arch_pc += 4
    # important !! Maybe hook library
    # see : https://joansivion.github.io/qilinglabs/
    return

ql.hook_code(midr_el1_hook)

Done

Thanks

Thanks MANSOUR Cyril release his writeup, help me alot.

Owner
Yuan
Yuan
Automatic Data-Regularized Actor-Critic (Auto-DrAC)

Auto-DrAC: Automatic Data-Regularized Actor-Critic This is a PyTorch implementation of the methods proposed in Automatic Data Augmentation for General

89 Dec 13, 2022
Learning Dynamic Network Using a Reuse Gate Function in Semi-supervised Video Object Segmentation.

Training Script for Reuse-VOS This code implementation of CVPR 2021 paper : Learning Dynamic Network Using a Reuse Gate Function in Semi-supervised Vi

HYOJINPARK 22 Jan 01, 2023
Implementation of TimeSformer, a pure attention-based solution for video classification

TimeSformer - Pytorch Implementation of TimeSformer, a pure and simple attention-based solution for reaching SOTA on video classification.

Phil Wang 602 Jan 03, 2023
HIVE: Evaluating the Human Interpretability of Visual Explanations

HIVE: Evaluating the Human Interpretability of Visual Explanations Project Page | Paper This repo provides the code for HIVE, a human evaluation frame

Princeton Visual AI Lab 16 Dec 13, 2022
TransferNet: Learning Transferrable Knowledge for Semantic Segmentation with Deep Convolutional Neural Network

TransferNet: Learning Transferrable Knowledge for Semantic Segmentation with Deep Convolutional Neural Network Created by Seunghoon Hong, Junhyuk Oh,

42 Jun 29, 2022
Evaluating deep transfer learning for whole-brain cognitive decoding

Evaluating deep transfer learning for whole-brain cognitive decoding This README file contains the following sections: Project description Repository

Armin Thomas 5 Oct 31, 2022
Nb workflows - A workflow platform which allows you to run parameterized notebooks programmatically

NB Workflows Description If SQL is a lingua franca for querying data, Jupyter sh

Xavier Petit 6 Aug 18, 2022
Multitask Learning Strengthens Adversarial Robustness

Multitask Learning Strengthens Adversarial Robustness

Columbia University 15 Jun 10, 2022
Implementation of the ivis algorithm as described in the paper Structure-preserving visualisation of high dimensional single-cell datasets.

Implementation of the ivis algorithm as described in the paper Structure-preserving visualisation of high dimensional single-cell datasets.

beringresearch 285 Jan 04, 2023
SAAVN - Sound Adversarial Audio-Visual Navigation,ICLR2022 (In PyTorch)

SAAVN SAAVN Code release for paper "Sound Adversarial Audio-Visual Navigation,IC

YinfengYu 10 Aug 30, 2022
The devkit of the nuPlan dataset.

The devkit of the nuPlan dataset.

Motional 264 Jan 03, 2023
Build an Amazon SageMaker Pipeline to Transform Raw Texts to A Knowledge Graph

Build an Amazon SageMaker Pipeline to Transform Raw Texts to A Knowledge Graph This repository provides a pipeline to create a knowledge graph from ra

AWS Samples 3 Jan 01, 2022
Official Implementation of DDOD (Disentangle your Dense Object Detector), ACM MM2021

Disentangle Your Dense Object Detector This repo contains the supported code and configuration files to reproduce object detection results of Disentan

loveSnowBest 51 Jan 07, 2023
Code for the paper "Reinforcement Learning as One Big Sequence Modeling Problem"

Trajectory Transformer Code release for Reinforcement Learning as One Big Sequence Modeling Problem. Installation All python dependencies are in envir

Michael Janner 269 Jan 05, 2023
DeFMO: Deblurring and Shape Recovery of Fast Moving Objects (CVPR 2021)

Evaluation, Training, Demo, and Inference of DeFMO DeFMO: Deblurring and Shape Recovery of Fast Moving Objects (CVPR 2021) Denys Rozumnyi, Martin R. O

Denys Rozumnyi 139 Dec 26, 2022
Easy-to-use library to boost AI inference leveraging state-of-the-art optimization techniques.

NEW RELEASE How Nebullvm Works • Tutorials • Benchmarks • Installation • Get Started • Optimization Examples Discord | Website | LinkedIn | Twitter Ne

Nebuly 1.7k Dec 31, 2022
The AugNet Python module contains functions for the fast computation of image similarity.

AugNet AugNet: End-to-End Unsupervised Visual Representation Learning with Image Augmentation arxiv link In our work, we propose AugNet, a new deep le

Ming 74 Dec 28, 2022
Trax — Deep Learning with Clear Code and Speed

Trax — Deep Learning with Clear Code and Speed Trax is an end-to-end library for deep learning that focuses on clear code and speed. It is actively us

Google 7.3k Dec 26, 2022
Code for the paper Task Agnostic Morphology Evolution.

Task-Agnostic Morphology Optimization This repository contains code for the paper Task-Agnostic Morphology Evolution by Donald (Joey) Hejna, Pieter Ab

Joey Hejna 18 Aug 04, 2022
My Body is a Cage: the Role of Morphology in Graph-Based Incompatible Control

My Body is a Cage: the Role of Morphology in Graph-Based Incompatible Control

yobi byte 29 Oct 09, 2022