用手机打 CTF 是种什么体验

刚刚阅读1回复0
kanwenda
kanwenda
  • 管理员
  • 注册排名1
  • 经验值175605
  • 级别管理员
  • 主题35121
  • 回复0
楼主

用智妙手机打CTF的球手:

用 iPhone 打 CTF (影视娱乐向)305 播映 · 2 赞成音频​ 大布景

前段时间 iSH 在 Apple Store 开卖了,之前不断抢不出 testflight 的进口产物,难能宝贵强控管的苹果公司会让那种 Terminal 类的应用范畴发布,所以第一时间阅读来玩儿。试验后发现能当做是两个单纯的 Linux 软件包,起码常见的指示都无所谓问题,刚都雅见看雪顶峰论坛有位 CTF,于是就尝尝,能不克不及用智妙手机来打五局 CTF :)

天然情况

iSH 是两个开放源码的 Terminal Emulator,在 iOS 中运转,接纳利用者态的 x86 号令演示以及 syscall 译者实现。iSH 中接纳的是 Alphine Linux 快照,所用 Docker 的应该都不会孤独。Alphine 是个十分轻量的 Linux 软件包,在官方网站上能间接阅读各收集平台预校对的快照,平常有试验Mach需求又不满足用户于 ramfs 的能接纳阅读的快照停止便利快速试验。

在 iSH 中早已有了两个单纯的 Alphine 天然情况,可能是原因在于苹果公司零售店审查的原因,在此中并没适用辅助东西保证理软件。他们能阅读两个完整的 iso 再次拆载,但是有更单纯的办法,间接从 Alphine Packages 中阅读动态校对版的 apk-tools-static:

wget http://dl-cdn.alpinelinux.org/alpine/latest-stable/main/x86/apk-tools-static-2.10.5-r1.apk tar -zxvf apk-tools-static-2.10.5-r1.apk ./sbin/apk.static -X https://mirrors.tuna.tsinghua.edu.cn --initdb add apk-tools apk update rm -rf ./sbin

他们用阅读的 apk-tools-static 来加拆 apk-tools,然后保证理软件 apk 就能恒定接纳了。若是挪用的时候没选定快照源,能接纳上面的指示批改为北京大学的快照源,鼎力推进国内的收集流量:

sed -i s/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g /etc/apk/repositories

后必要的辅助东西就能另行加拆了,我那儿只必要 radare2 和 Python:

apk add radare2 apk add python3

试题是看雪 CTF2020 的打卡题: https://ctf.pediy.com/game-season_fight-158.htm

Write Up

写做文过程在该文结尾的音频中早已能看见了,那儿仍是用文本如是说下写做文路子。

详细来说 rabin2 查阅目的法式的重要信息:

$ rabin2 -I kctf2020.exe arch x86 baddr 0x140000000 binsz 12288 bintype pe bits 64 canary false retguard false class PE32+ cmp.csum 0x0000bcb6 compiled Thu Nov 12 03:49:32 2020 crypto false dbg_file D:\Users\admin\Documents\Visual Studio 2015\Projects\ctf2020\ConsoleApplication1\x64\Release\ConsoleApplication1.pdb endian little havecode true hdr.csum 0x00000000 guid 4EF50FB8F5E74CC481D01589FC111B1A1 laddr 0x0 lang c linenum false lsyms false machine AMD 64 maxopsz 16 minopsz 1 nx true os windows overlay false cc ms pcalign 0 pic true relocs false signed false sanitiz false static false stripped false subsys Windows CUI va true

能看见是 PE64 的的法式,鉴于是打卡题,所以就间接逆向阐发了:

$ r2 kctf2020.exe -- [0x14000154c]> s main [0x140001000]> af [0x140001000]> pd 20 ;-- section..text: ┌ 459: int main (int argc, char **argv, char **envp); │ bp: 7 (vars 7, args 0) │ sp: 14 (vars 14, args 0) │ rg: 0 (vars 0, args 0) │ 0x140001000 4055 push rbp ; [00] -r-x section size 8192 named .text │ 0x140001002 488dac24c0fe. lea rbp, [rsp - 0x140] │ 0x14000100a 4881ec400200. sub rsp, 0x240 │ 0x140001011 488b05e82f00. mov rax, qword [section..data] ; [0x140004000:8]=0x2b992ddfa232 ; "2\xa2\xdf-\x99+" │ 0x140001018 4833c4 xor rax, rsp │ 0x14000101b 488985300100. mov qword [var_130h], rax │ 0x140001022 33d2 xor edx, edx │ 0x140001024 488d4c2430 lea rcx, [var_30h] │ 0x140001029 41b800010000 mov r8d, 0x100 ; 256 │ 0x14000102f e8ce0e0000 call 0x140001f02 │ 0x140001034 33d2 xor edx, edx │ 0x140001036 488d4d30 lea rcx, [var_bp_30h] │ 0x14000103a 41b800010000 mov r8d, 0x100 ; 256 │ 0x140001040 e8bd0e0000 call 0x140001f02 │ 0x140001045 488d0dd42100. lea rcx, str.KCTF_2020 ; 0x140003220 ; "KCTF 2020!\n" │ 0x14000104c e8ff010000 call 0x140001250 │ 0x140001051 488d0dd82100. lea rcx, str.http:__bbs.pediy.com ; 0x140003230 ; "http://bbs.pediy.com\n" │ 0x140001058 e8f3010000 call 0x140001250 │ 0x14000105d 488d0de42100. lea rcx, str.Please_input_your_flag: ; 0x140003248 ; "Please input your flag: " │ 0x140001064 e8e7010000 call 0x140001250

在 0x140001250 地址处经常有挪用,按照参数能推测是打印函数,验证一下:

[0x140001000]> s 0x140001250 [0x140001250]> af [0x140001250]> pdf ; CALL XREFS from main @ 0x14000104c, 0x140001058, 0x140001064, 0x14000119b, 0x1400011ab ┌ 85: int printf (const char *format); │ ; var int64_t var_20h_2 @ rsp+0x20 │ ; var int64_t var_8h @ rsp+0x50 │ ; var int64_t var_10h @ rsp+0x58 │ ; var int64_t var_18h @ rsp+0x60 │ ; var int64_t var_20h @ rsp+0x68 │ ; arg int64_t arg1 @ rcx │ ; arg int64_t arg2 @ rdx │ ; arg int64_t arg3 @ r8 │ ; arg int64_t arg4 @ r9 │ 0x140001250 48894c2408 mov qword [var_8h], rcx ; arg1 │ 0x140001255 4889542410 mov qword [var_10h], rdx ; arg2 │ 0x14000125a 4c89442418 mov qword [var_18h], r8 ; arg3 │ 0x14000125f 4c894c2420 mov qword [var_20h], r9 ; arg4 │ 0x140001264 53 push rbx │ 0x140001265 56 push rsi │ 0x140001266 57 push rdi │ 0x140001267 4883ec30 sub rsp, 0x30 │ 0x14000126b 488bf9 mov rdi, rcx │ 0x14000126e 488d742458 lea rsi, [var_10h] │ 0x140001273 b901000000 mov ecx, 1 │ 0x140001278 ff150a1f0000 call qword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll___acrt_iob_func] ; [0x140003188:8]=0x3a98 reloc.api_ms_win_crt_stdio_l1_1_0.dll___acrt_iob_func │ 0x14000127e 488bd8 mov rbx, rax │ 0x140001281 e8baffffff call fcn.140001240 │ 0x140001286 4533c9 xor r9d, r9d │ 0x140001289 4889742420 mov qword [var_20h_2], rsi │ 0x14000128e 4c8bc7 mov r8, rdi │ 0x140001291 488bd3 mov rdx, rbx │ 0x140001294 488b08 mov rcx, qword [rax] │ 0x140001297 ff15e31e0000 call qword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll___stdio_common_vfprintf] ; [0x140003180:8]=0x3aaa reloc.api_ms_win_crt_stdio_l1_1_0.dll___stdio_common_vfprintf │ 0x14000129d 4883c430 add rsp, 0x30 │ 0x1400012a1 5f pop rdi │ 0x1400012a2 5e pop rsi │ 0x1400012a3 5b pop rbx └ 0x1400012a4 c3 ret

公然是打印函数,间接重定名一下,清新一些:

[0x140001250]> af printf [0x140001250]> s- [0x140001000]> pd 20 ;-- section..text: ┌ 459: int main (int argc, char **argv, char **envp); │ bp: 7 (vars 7, args 0) │ sp: 14 (vars 14, args 0) │ rg: 0 (vars 0, args 0) │ 0x140001000 4055 push rbp ; [00] -r-x section size 8192 named .text │ 0x140001002 488dac24c0fe. lea rbp, [rsp - 0x140] │ 0x14000100a 4881ec400200. sub rsp, 0x240 │ 0x140001011 488b05e82f00. mov rax, qword [section..data] ; [0x140004000:8]=0x2b992ddfa232 ; "2\xa2\xdf-\x99+" │ 0x140001018 4833c4 xor rax, rsp │ 0x14000101b 488985300100. mov qword [var_130h], rax │ 0x140001022 33d2 xor edx, edx │ 0x140001024 488d4c2430 lea rcx, [var_30h] │ 0x140001029 41b800010000 mov r8d, 0x100 ; 256 │ 0x14000102f e8ce0e0000 call 0x140001f02 │ 0x140001034 33d2 xor edx, edx │ 0x140001036 488d4d30 lea rcx, [var_bp_30h] │ 0x14000103a 41b800010000 mov r8d, 0x100 ; 256 │ 0x140001040 e8bd0e0000 call 0x140001f02 │ 0x140001045 488d0dd42100. lea rcx, str.KCTF_2020 ; 0x140003220 ; "KCTF 2020!\n" │ 0x14000104c e8ff010000 call printf ; int printf(const char *format) │ 0x140001051 488d0dd82100. lea rcx, str.http:__bbs.pediy.com ; 0x140003230 ; "http://bbs.pediy.com\n" │ 0x140001058 e8f3010000 call printf ; int printf(const char *format) │ 0x14000105d 488d0de42100. lea rcx, str.Please_input_your_flag: ; 0x140003248 ; "Please input your flag: " │ 0x140001064 e8e7010000 call printf ; int printf(const char *format)

同理,把 scanf 也重定名上,先看法式结尾的逻辑:

│ 0x140001069 41b800010000 mov r8d, 0x100 ; 256 │ 0x14000106f 488d542430 lea rdx, [var_30h] │ 0x140001074 488d0de92100. lea rcx, [0x140003264] ; "%s" │ 0x14000107b e860010000 call scanf ; int scanf(const char *format) │ 0x140001080 488d542430 lea rdx, [var_30h] │ 0x140001085 4883c9ff or rcx, 0xffffffffffffffff │ 0x140001089 0f1f80000000. nop dword [rax] │ ┌─> 0x140001090 48ffc1 inc rcx │ ╎ 0x140001093 803c0a00 cmp byte [rdx + rcx], 0 │ └─< 0x140001097 75f7 jne 0x140001090 │ 0x140001099 83f90c cmp ecx, 0xc ; 12 │ ┌─< 0x14000109c 0f8502010000 jne 0x1400011a4 │ │ 0x1400010a2 807c243066 cmp byte [var_30h], 0x66 │ ┌──< 0x1400010a7 0f85f7000000 jne 0x1400011a4 │ ││ 0x1400010ad 807c24316c cmp byte [var_31h], 0x6c │ ┌───< 0x1400010b2 0f85ec000000 jne 0x1400011a4 │ │││ 0x1400010b8 807c243261 cmp byte [var_32h], 0x61 │ ┌────< 0x1400010bd 0f85e1000000 jne 0x1400011a4 │ ││││ 0x1400010c3 807c243367 cmp byte [var_33h], 0x67 │ ┌─────< 0x1400010c8 0f85d6000000 jne 0x1400011a4 │ │││││ 0x1400010ce 807c24347b cmp byte [var_34h], 0x7b │ ┌──────< 0x1400010d3 0f85cb000000 jne 0x1400011a4 │ ││││││ 0x1400010d9 807c243b7d cmp byte [var_3bh], 0x7d │ ┌───────< 0x1400010de 0f85c0000000 jne 0x1400011a4

var_30h 是输入的字符串,别离停止字节和长度比对,要求输入字符串长度为 12,而且格局为 flag{xxxxxx},那儿有位技巧是 radare2 中 VV 形式下的跳转:

tab/shift+tab: 跳转到下两个/前两个 basic blockt/f: 跳转到 true/false 分收u/U: undo/redo 跳转

然后是 flag 中间字符的判断:

0x1400010e4 440fb74c2439 movzx r9d, word [var_39h] 0x1400010ea 4c8d442420 lea r8, [var_20h] 0x1400010ef 448b542435 mov r10d, dword [var_35h] 0x1400010f4 33c0 xor eax, eax 0x1400010f6 6644894c2424 mov word [var_24h], r9w 0x1400010fc 8bd0 mov edx, eax 0x1400010fe 4489542420 mov dword [var_20h], r10d 0x140001103 0f1f4000 nop dword [rax] 0x140001107 660f1f840000. nop word [rax + rax]

那儿接纳 mov dword 来停止拷贝,将 var_35h 拷贝 到 var_20h 中,同时 r8 存放器指向 var_20h。接着先轮回逐个判断字符c - 0x30能否小于 9,若是有大于 9 的就报错:

┌─> 0x140001110 410fb608 movzx ecx, byte [r8] ╎ 0x140001114 80e930 sub cl, 0x30 ; 48 ╎ 0x140001117 80f909 cmp cl, 9 ; 9 ┌──< 0x14000111a 0f8784000000 ja 0x1400011a4 │╎ 0x140001120 ffc2 inc edx │╎ 0x140001122 49ffc0 inc r8 │╎ 0x140001125 83fa06 cmp edx, 6 ; 6 │└─< 0x140001128 72e6 jb 0x140001110 │ 0x14000112a ...

接着颠末上面的判断,记得 var_30h 是他们的输入,长度为 12,格局为 flag{xxxxxx}:

0x14000112a 0fb6542437 movzx edx, byte [var_37h] 0x14000112f 4c8d053e2100. lea r8, [0x140003274] ; "2;=EFI" 0x140001136 0fb64c2436 movzx ecx, byte [var_36h] 0x14000113b 80ea30 sub dl, 0x30 ; 48 0x14000113e 80e930 sub cl, 0x30 ; 48 0x140001141 44885530 mov byte [var_bp_30h], r10b 0x140001145 4102ca add cl, r10b 0x140001148 4180e930 sub r9b, 0x30 ; 48 0x14000114c 02d1 add dl, cl 0x14000114e 884d31 mov byte [var_bp_31h], cl 0x140001151 0fb64c2438 movzx ecx, byte [var_38h] 0x140001156 80e930 sub cl, 0x30 ; 48 0x140001159 885532 mov byte [var_bp_32h], dl 0x14000115c 02ca add cl, dl 0x14000115e 488d5530 lea rdx, [var_bp_30h] 0x140001162 4402c9 add r9b, cl 0x140001165 884d33 mov byte [var_bp_33h], cl 0x140001168 0fb64c243a movzx ecx, byte [var_3ah] 0x14000116d 80e930 sub cl, 0x30 ; 48 0x140001170 44884d34 mov byte [var_bp_34h], r9b 0x140001174 4102c9 add cl, r9b 0x140001177 884d35 mov byte [var_bp_35h], cl 0x14000117a 660f1f440000 nop word [rax + rax] ┌─> 0x140001180 0fb60c02 movzx ecx, byte [rdx + rax] ╎ 0x140001184 48ffc0 inc rax ╎ 0x140001187 413a4c00ff cmp cl, byte [r8 + rax - 1] ┌──< 0x14000118c 7516 jne 0x1400011a4 │╎ 0x14000118e 4883f807 cmp rax, 7 ; 7 │└─< 0x140001192 75ec jne 0x140001180 │ 0x140001194 488d0de52000. lea rcx, [0x140003280] ; "You are winner!\n" │ 0x14000119b e8b0000000 call printf ; int printf(const char *format)

设flag{}中间的内容为flag,那儿的逻辑能写成伪代码:

buf[0] = flag[0] buf[1] = buf[0] + flag[1] - 48 buf[2] = buf[1] + flag[2] - 48 buf[3] = buf[2] + flag[3] - 48 buf[4] = buf[3] + flag[4] - 48 buf[5] = buf[4] + flag[5] - 48 if buf == "2;=EFI": printf("You are winner!\n")

反向计算,可得:

flag[0] = buf[0] flag[1] = buf[1] - buf[0] + 48 flag[2] = buf[2] - buf[1] + 48 flag[3] = buf[3] - buf[2] + 48 flag[4] = buf[4] - buf[3] + 48 flag[5] = buf[5] - buf[4] + 48

所以计算的 flag 为:

$ ./solve.py flag: b292813

最末谜底应该是 flag{292813},若是有 windows 天然情况的话能停止动态验证,在 Linux/MacOS 天然情况中能用 wine 来停止验证,如下:

$ wine64 kctf2020.exe 0025:err:plugplay:runloop_thread Couldnt open IOHIDManager. 0009:fixme:vcruntime:__telemetry_main_invoke_trigger (0x0) KCTF 2020! http://bbs.pediy.com Please input your flag: 0009:fixme:msvcrt:MSVCRT__stdio_common_vfscanf options 3 not handled flag{292813} You are winner! 0009:fixme:vcruntime:__telemetry_main_return_trigger (0x0) 跋文

加拆了 iSH 后,我的智妙手机时间分配酿成了如许:

智妙手机上的 Terminal 能用来做什么呢?那儿能列举一些:

用来 ssh 登录到办事器停止办理用来随时查阅 man page用来编写和运转主动化脚本停止一些单纯的指示行操做...

此中 ssh 对我来说是个刚需,因为在此之前苹果公司上不断没两个好用且免费的 ssh client,只能用 Termius 勉强过活。不外可惜的是因为苹果公司的战略,iSH 暂时还不克不及在后台运转,否则间接 ssh -R 还能当做隧道用,岂不美哉?

当然,iSH 仍是有良多局限性的,好比只能演示 x86 的号令集,并且因为是软件演示,因而运转效率比力低。若是要施行复杂的使命,好比 gcc 校对大型项目,仍是更好在 PC 上运转了。

0
回帖 返回旅游

用手机打 CTF 是种什么体验 期待您的回复!

取消
载入表情清单……
载入颜色清单……
插入网络图片

取消确定

图片上传中
编辑器信息
提示信息