吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2425|回复: 8
收起左侧

[CTF] qiling framework + qilingLab x86_64 题解

[复制链接]
幼儿园小班 发表于 2023-8-28 03:27
本帖最后由 幼儿园小班 于 2023-9-8 11:33 编辑

qiling framework + qilingLab x86_64 题解

环境

先模拟运行

ql = Qiling(["qilinglab-x86_64"], "rootfs/x8664_linux",
            verbose=QL_VERBOSE.OFF, multithread=True)
ql.run()
  • 运行后发现报错.
    • unicorn.unicorn.UcError: Invalid memory read (UC_ERR_READ_UNMAPPED)
    • 说明内存读取不到.不用慌,这是因为第一题我们还没解出来.解出来就解决了.原因下面会讲

第1题

  • 先看下ida反编译的伪c代码.

image-20230828014725142

  • 比较简单,就是要地址0x1337的值等于1337即可.但是我们之前一运行就报错.是因为这里的0x1337不存在,所以报错.

  • 接下来我们直接写代码

  • def challenge1():
      ql.mem.map(0x1000, 0x1000)
      ql.mem.write(0x1337, ql.pack16(1337))

第2题

image-20230828020206027

  • 逻辑解释

  • 调用uname函数赋值给name变量

  • name.sysname 要等于 "QilingOS"

  • name.version 要等于 "ChallengeStart"

  • 所以我们只需要直接修改 uname函数即可

  • def challenge2():
      def my_syscall_uname(q: Qiling, *args):
          rdi = ql.arch.regs.rdi
          ql.mem.write(rdi, b'QilingOS\x00')
          ql.mem.write(rdi + 65 * 3, b'ChallengeStart\x00')
    
      ql.os.set_api("uname", my_syscall_uname, QL_INTERCEPT.EXIT)
  • 可能各位会疑问,为什么写rdi和rdi+65*3,大家看张图即可明白了

  • image-20230828021355516

第3题

image-20230828021512165

  • 逻辑解释

  • 打开/dev/urandom

  • 取0x20个字符放到buf

  • 取1个字符放到v5

  • 生成一个32位的字符放到v7

  • 对比buf的每个字符等于v7的每个字符,且buf的字符不等于v5

  • 所以解题方式就是做一个假的 /dev/urandom 和 一个我们自己的getrandom

  • def challenge3():
      class FKUrandom(QlFsMappedObject):
          def read(self, expected_len):
              if expected_len > 1:
                  return b"\x65" * expected_len
              else:
                  return b"\x00"
    
          def fstat(self):
              return -1
    
          def close(self):
              return 0
    
      def my_get_random(q: Qiling, *args):
          p = q.os.resolve_fcall_params({"buf": POINTER, "count": SIZE_T, "flags": INT})
          if p["count"] == 32:
              q.mem.write(p["buf"], b"\x65" * 32)
          return 0
    
      ql.add_fs_mapper("/dev/urandom", FKUrandom())
    
      ql.os.set_api("getrandom", my_get_random, QL_INTERCEPT.CALL)

第4题

  • 该题反编译看不到伪c代码,所以我们直接看汇编码

  • image-20230828022258784

  • image-20230828022514993

  • 逻辑解释

  • 初始化 [rbp+var_8] = 0 和 [rbp+var_4] = 0

  • 0xe43处进行cmp判断,如果相等则死循环

  • 所以我们只需要让他们两的值不同即可

  • 两种解法:

    • 第一种:

    • 直接在0xe43处修改eax的值

    • def challenge4():
        base_ptr = ql.mem.get_lib_base("qilinglab-x86_64")
        hook_addr = base_ptr + 0xe43
      
        def update_eax(q: Qiling, *args):
            q.arch.regs.eax = 1
      
        ql.hook_address(update_eax, hook_addr)
    • 第二种:

    • 直接在赋值后进行修改,让其不同

    • def challenge4_1():
        base_ptr = ql.mem.get_lib_base("qilinglab-x86_64")
        hook_addr = base_ptr + 0xe33
      
        def update_var8(q: Qiling, *args):
            rbp = q.arch.regs.rbp
            q.mem.write(rbp - 0x8, b"\x01")
      
        ql.hook_address(update_var8, hook_addr)

第5题

  • image-20230828023259185

  • 逻辑解释

  • v5[0-4] = 0

  • V5[8-12]=rand() 随机数

  • 所以解题方式就是直接改rand 让其返回0即可

    • def challenge5():
      def my_rand(q: Qiling, *args):
          q.arch.regs.eax = 0
      
      ql.os.set_api("rand", my_rand, QL_INTERCEPT.EXIT)

第6题

  • image-20230828024829697

  • 逻辑解释,直接一个死循环....参考第4题解题思路

  • def challenge6():
      base_ptr = ql.mem.get_lib_base("qilinglab-x86_64")
      hook_addr = base_ptr + 0xf16
    
      def update_rax(q: Qiling, *args):
          q.arch.regs.rax = 0
    
      ql.hook_address(update_rax, hook_addr)

第7题

image-20230828025012040

  • 逻辑解释,直接睡死.....

  • 解题思路,修改sleep即可

  • def challenge7():
      def my_sleep(q: Qiling, *args):
          q.arch.regs.edi = 0
          return 0
    
      ql.os.set_api("sleep", my_sleep, QL_INTERCEPT.ENTER)

第8题

image-20230828025151930

  • 逻辑解释

  • v2 申请0x18大小的字节, 就是24个字节

  • 而dword=4字节,所以v2是6个dowrd

  • qword = 8个字节.

  • 为v2起始位置指向的地址 申请0x1e的空间,这里相当于v2[0] + v2[1] = malloc(0x1euLL)

  • v2[2] 和 v2[3] 分别等于 1337 和 1039980266

  • 所以v2的第二个指向地址的值是 1039980266 << 32 + 1337,为什么1039980266在前,因为要注意大小端问题,这里为什么要这么算,因为我们要取一个内存魔数,然后通过内存搜索来定位该结构.

  • 为v2的起始位置指向的地址赋值成 "Random data"

  • v2+2相当于v2的第三个指向的地址的值=a1,这个就是check值.

  • 所以解题方式就是找到这个结构,然后修改第三个值为1即可.

  • def challenge8():
      def hook(q: Qiling, *args):
          magic = (1039980266 << 32) + 1337
          addr_list = q.mem.search(q.pack64(magic))
          for addr in addr_list:
              st_addr = addr - 8
              tmp_struct = q.mem.read(st_addr, 24)
              str_addr, _, check_addr = struct.unpack("QQQ", tmp_struct)
              # print(q.mem.string(str_addr))
              if q.mem.string(str_addr) == "Random data":
                  # print("Check", q.mem.read(q.arch.regs.rdx, 8))
                  q.mem.write(check_addr, q.pack8(1))
    
      base_ptr = ql.mem.get_lib_base("qilinglab-x86_64")
      ql.hook_address(hook, base_ptr + 0xfb5)

第9题

image-20230828031401868

  • 逻辑解释

  • 对src赋值"aBcdeFghiJKlMnopqRstuVWxYz"

  • dest = src 即 dest = "aBcdeFghiJKlMnopqRstuVWxYz"

  • 循环对dest做小写处理

  • 判断src要等于dest

  • 解题思路

    • 所以我们只需要处理strcmp或者tolower函数即可.

    • 建议不要处理strcmp 因为第10题也用到了这个不利于我们学习.会直接把第10题也过了.

    • 所以我们处理tolower

    • def challenge9():
      def hook(q: Qiling, *args):
          p = q.os.resolve_fcall_params({"s": BYTE})
          # print(p["s"])
          q.arch.regs.eax = p["s"]
      
      ql.os.set_api("tolower", hook, QL_INTERCEPT.EXIT)

第10题

image-20230828031752756

  • 逻辑解释

  • 打开文件 /proc/self/cmdline

  • 读取 0x3f 字节,赋值给buf

  • 对buf进行处理,0值赋值成32

  • 判断buf是否等于 "qilinglab"

  • 所以解题思路就是,直接模拟该文件,让read函数直接读到"qilinglab" 即可

  • def challenge10():
      class FSHook(QlFsMappedObject):
          def read(self, expected_len):
              return "qilinglab".encode()
    
          def close(self):
              return 0
    
      ql.add_fs_mapper("/proc/self/cmdline", FSHook())

第11题

image-20230828032049842

  • 逻辑解释

  • 执行汇编指令 cpuid

  • 然后判断 rbx+rcx组合后的值要等于  0x696C6951614C676ELL

  • 同时 rdx的值要等于  538976354

  • 这题比较关键的是 cpuid,不清楚的小伙伴可以自行查询资料.

  • 所以我们的解题思路就是在执行cpuid的时候直接不执行,同时对rbc rcx rdx进行赋值即可

  • def challenge11():
      def hook1(q: Qiling, address, size):
          if ql.mem.read(address, size) == b'\x0f\xa2':
              regs = ql.arch.regs
              regs.ebx = 0x696C6951
              regs.ecx = 0x614C676E
              regs.edx = 0x20202062
              regs.rip += 2
    
      ql.hook_code(hook1)

到此为止,11题全部拿下.受益匪浅,今后准备在有空的情况下,尝试用qiling框架刷一下ctf的逆向题,然后分享给大家一起学习qiling这个框架.该框架真的非常好.

其中第8题和第11题确实学到了很多的东西......

免费评分

参与人数 5吾爱币 +11 热心值 +5 收起 理由
笙若 + 1 + 1 谢谢@Thanks!
Hmily + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
woyucheng + 1 + 1 谢谢@Thanks!
caojian162411 + 1 + 1 用心讨论,共获提升!
为之奈何? + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

youxiaxy 发表于 2023-8-28 08:10
解析的不错。感谢分享
yb66vs 发表于 2023-8-28 08:50
AA082 发表于 2023-8-28 09:27
weiyanli 发表于 2023-8-28 10:50
学习中,感谢大神分享
头像被屏蔽
appointment 发表于 2023-8-28 11:03
提示: 该帖被管理员或版主屏蔽
Hmily 发表于 2023-9-6 17:09
@幼儿园小班 有个图好像地址好像不对:image-20230828021355516.png
 楼主| 幼儿园小班 发表于 2023-9-8 11:33
Hmily 发表于 2023-9-6 17:09
@幼儿园小班 有个图好像地址好像不对:image-20230828021355516.png

感谢,之前都没发现,已经修复了
abc14258 发表于 2023-9-8 16:17
牛掰啊大佬学到了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 12:21

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表