Artificial truth

The more you see, the less you believe.

[archives] [latest] | [homepage] | [atom/rss]

Solving game2 from the badge of Black Alps 2017 with radare2
Sat 18 November 2017 — download

Black Alps was a nice conference where I gave yet another talk about Snuffleupagus (you can get our slides here, those time including Winnie the Pooh), and happened to have a pretty amazing badge:

shitty image of the badge

The badge was of course full of flag to find, some by "manually fuzzing" the menus, others by playing with bluetooth, … We spent some time on it, but apparently, the USB-to-serial thingy was "oddly wired", preventing us from dumping the firmware with my phone charger cable, and I didn't have anything fancier, like an UART in my pocket.

So I focused on doing the game2, which was about reversing, that you could play by connecting to the badge with serial-over-usb

minicom --device /dev/ttyUSB0
Welcome to minicom 2.7

OPTIONS: I18n 
Compiled on Feb  7 2016, 13:37:27.
Port /dev/ttyUSB0, 14:45:34

Press CTRL-A Z for help on special keys

> help
   show           Show information
   stat           Show cow statistics
   name           Set cow name
   game1          Can you find the password ?
   game2          Reversing challenge
   game3          Can you spot the cheat code ?
   help           Show help on available commands
> game2
Missing argument.
> game2 hunter2
Here is my password checking function. Have fun !
3641008202003c19979859920206a2a061a79954a202073b99979a50a20209920205979a4b2ba8a7994a9202023b8887994692020a82a0788799419202084c8887993d8202014c39979839a202032cd99098309090
Incorrect password :(
> 

The chip used is an ESP-WROOM-32, using the xtensa cpu architecture, and of course, radare2 supports it:

$ rasm2 -L | grep xtensa
_dAe  32         xtensa      GPL3    XTensa CPU
$

I could have done the challenge only with rasm2, but it's funnier with radare2:

$ r2 -a xtensa -
[0x00000000]> wx 3641008202003c19979859920206a2a061a79954a202073b99979a50a20209920205979a4b2ba8a7994a9202023b8887994692020a82a0788799419202084c8887993d8202014c39979839a202032cd9909830909074979a2f220204fb8887122b0c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c121df0
[0x00000000]> aaaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Emulate code to find computed references (aae)
[x] Analyze consecutive function (aat)
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[x] Type matching analysis for all functions (afta)
[0x00000000]> VV
                                                                   __0x0__
                                                                      
                                                                      └─┐
                                                               ┌─────┘   
                                                                        
                                                             __0xb__  __0x65__
                                                                
                                                         ┌─────┘ └─┐
                                                                  
                                                       __0x14__ __0x69__
                                                          
                                                   ┌─────┘ └─┐
                                                            
                                                __0x1c__  __0x6d__
                                                    
                                             ┌─────┘ └─┐ 
                                                      
                                           __0x25__  __0x71__
                                              
                                       ┌─────┘ └─┐
                                                
                                    __0x2a__  __0x75__
                                        
                                 ┌─────┘ └─┐ 
                                          
                              __0x32__  __0x79__
                                  
                           ┌─────┘ └─┐  
                                    
                        __0x3b__  __0x7d__
                            
                     ┌─────┘ └─┐   
                              
                  __0x43__  __0x81__
                      
               ┌─────┘ └─┐  
                        
            __0x4b__  __0x85__
                
         ┌─────┘ └─┐  
                  
      __0x59__  __0x89__
          
   ┌─────┘ └─┐
            
__0x61__  __0x8d__

It look like a chain of check for each of the eleven characters of the password.

[0x00000065]> pdf
 (fcn) fcn.00000000 145
 0x00000000      364100         entry a1, 32
 0x00000001      410082         l32r a4, 0xfffe0804
 0x00000004      02003c         l8ui a0, a0, 60
 0x00000007      1997           s32i.n a1, a7, 36
 0x00000009      9859           l32i.n a9, a9, 20
 0x0000000b      920206         l8ui a9, a2, 6
 0x0000000e      a2a061         movi a10, 97
 0x00000011      a79954         bne a9, a10, 0x00000069
 0x00000014      a20207         l8ui a10, a2, 7
 0x00000017      3b99           addi.n a9, a9, 3
 0x00000019      979a50         bne a10, a9, 0x0000006d
 0x0000001c      a20209         l8ui a10, a2, 9
 0x0000001f      920205         l8ui a9, a2, 5
 0x00000022      979a4b         bne a10, a9, 0x00000071
 0x00000025      2ba8           addi.n a10, a8, 2
 0x00000027      a7994a         bne a9, a10, 0x00000075
 0x0000002a      920202         l8ui a9, a2, 2
 0x0000002d      3b88           addi.n a8, a8, 3
 0x0000002f      879946         bne a9, a8, 0x00000079
 0x00000032      92020a         l8ui a9, a2, 10
 0x00000035      82a078         movi a8, 120
 0x00000038      879941         bne a9, a8, 0x0000007d
 0x0000003b      920208         l8ui a9, a2, 8
 0x0000003e      4c88           movi.n a8, 72
 0x00000040      87993d         bne a9, a8, 0x00000081
 0x00000043      820201         l8ui a8, a2, 1
 0x00000046      4c39           movi.n a9, 67
 0x00000048      979839         bne a8, a9, 0x00000085
 0x0000004b      a20203         l8ui a10, a2, 3
 0x0000004e      2cd9           movi.n a9, 45
 0x00000050      909830         xor a9, a8, a9
 0x00000053      909074         extui a9, a9, 0, 8
 0x00000056      979a2f         bne a10, a9, 0x00000089
 0x00000059      220204         l8ui a2, a2, 4
 0x0000005c      fb88           addi.n a8, a8, 15
 0x0000005e      87122b         beq a2, a8, 0x0000008d
 0x00000061      0c02           movi.n a2, 0
 0x00000063      1df0           retw.n
 0x00000065      0c02           movi.n a2, 0
 0x00000067      1df0           retw.n
 0x00000069      0c02           movi.n a2, 0
 0x0000006b      1df0           retw.n
 0x0000006c      f00c02         andb b0, b12, b15
 0x0000006f      1df0           retw.n
 0x00000071      0c02           movi.n a2, 0
 0x00000073      1df0           retw.n
 0x00000075      0c02           movi.n a2, 0
 0x00000077      1df0           retw.n
 0x00000079      0c02           movi.n a2, 0
 0x0000007b      1df0           retw.n
 0x0000007d      0c02           movi.n a2, 0
 0x0000007f      1df0           retw.n
 0x00000081      0c02           movi.n a2, 0
 0x00000082      021df0         l16ui a0, a13, 0x1e0
 0x00000085      0c02           movi.n a2, 0
 0x00000087      1df0           retw.n
 0x00000089      0c02           movi.n a2, 0
 0x0000008b      1df0           retw.n
 0x0000008d      0c12           movi.n a2, 1
 0x0000008f      1df0           retw.n

If you struggle a bit to read the listing, you can set asm.describe to true, to get a handy description, but basically, it boils down to movi, beq and l8ui (as in load a byte as an unsigned integer), so it's pretty easy.

I annotated the listing by hand using the ; command in visual mode, and dis to set the immediate as a string to have a better overview:

[0x00000065]> pdf
 (fcn) fcn.00000000 145
 0x00000000      364100         entry a1, 32             ; subroutine entry, 32 bit stack frame
  0x00000003      820200         l8ui a8, a2, 0          ; a8 = a2[0]
  0x00000006      3c19           movi.n a9, '1'          ; a9 = '1'
  0x00000008      979859         bne a8, a9, 0x00000065  ; if a2[0] != a9; goto 0x65
 0x0000000b      920206         l8ui a9, a2, 6           ; a9 = a2[6]
 0x0000000e      a2a061         movi a10, 'a'            ; a10 = 'a'
 0x00000011      a79954         bne a9, a10, 0x00000069  ; if a2[6] != 'a'; goto end
 0x00000014      a20207         l8ui a10, a2, 7          ; a10 = a2[7]
 0x00000017      3b99           addi.n a9, a9, 3         ; a9 = 'd'
 0x00000019      979a50         bne a10, a9, 0x0000006d  ; if a2[7] != 'c'; goto end
 0x0000001c      a20209         l8ui a10, a2, 9          ; a10 = a2[9]
 0x0000001f      920205         l8ui a9, a2, 5           ; a9 = a2[5]
 0x00000022      979a4b         bne a10, a9, 0x00000071  ; if a2[9] != a2[5]; goto end
 0x00000025      2ba8           addi.n a10, a8, 2        ; a10 = '3'
 0x00000027      a7994a         bne a9, a10, 0x00000075  ; if a2[5] != a10; goto end
 0x0000002a      920202         l8ui a9, a2, 2           ; a9 = a2[2]
 0x0000002d      3b88           addi.n a8, a8, 3         ; a8 = '4'
 0x0000002f      879946         bne a9, a8, 0x00000079   ; if a2[2] != '4'; goto end
 0x00000032      92020a         l8ui a9, a2, 10          ; a9 = a2[10]
 0x00000035      82a078         movi a8, 'x'             ; a8 = 'x'
 0x00000038      879941         bne a9, a8, 0x0000007d   ; if a2[10] != 'x'; goto end
 0x0000003b      920208         l8ui a9, a2, 8           ; a9 = a2[8]
 0x0000003e      4c88           movi.n a8, 'H'           ; a8 = 'H'
 0x00000040      87993d         bne a9, a8, 0x00000081   ; if a2[8] != 'H'
 0x00000043      820201         l8ui a8, a2, 1           ; a8 = a2[1]
 0x00000046      4c39           movi.n a9, 'C'           ; a9 = 'C'
 0x00000048      979839         bne a8, a9, 0x00000085   ; if a2[1] 1= 'C'; goto end
 0x0000004b      a20203         l8ui a10, a2, 3          ; a10 = a2[3]
 0x0000004e      2cd9           movi.n a9, 45            ; a9 = 45
 0x00000050      909830         xor a9, a8, a9           ; a9 ^= '67'
 0x00000053      909074         extui a9, a9, 0, 8       ; a9 = a9[0:8]
 0x00000056      979a2f         bne a10, a9, 0x00000089  ; if a2[3] != 'n'; goto end
 0x00000059      220204         l8ui a2, a2, 4           ; a2 = a2[4]
 0x0000005c      fb88           addi.n a8, a8, 15        ; a8 = 'R'
 0x0000005e      87122b         beq a2, a8, 0x0000008d   ; if a2[4] != 'R'; goto end
 0x00000061      0c02           movi.n a2, 0             ; return value = 0
 0x00000063      1df0           retw.n                   ; return
 0x00000065      0c02           movi.n a2, 0
 0x00000067      1df0           retw.n
 0x00000069      0c02           movi.n a2, 0
 0x0000006b      1df0           retw.n
 0x0000006c      f00c02         andb b0, b12, b15
 0x0000006f      1df0           retw.n
 0x00000071      0c02           movi.n a2, 0
 0x00000073      1df0           retw.n
 0x00000075      0c02           movi.n a2, 0
 0x00000077      1df0           retw.n
 0x00000079      0c02           movi.n a2, 0
 0x0000007b      1df0           retw.n
 0x0000007d      0c02           movi.n a2, 0
 0x0000007f      1df0           retw.n
 0x00000081      0c02           movi.n a2, 0
 0x00000082      021df0         l16ui a0, a13, 0x1e0
 0x00000085      0c02           movi.n a2, 0
 0x00000087      1df0           retw.n
 0x00000089      0c02           movi.n a2, 0
 0x0000008b      1df0           retw.n
 0x0000008d      0c12           movi.n a2, 1              ; return value = 1
 0x0000008f      1df0           retw.n                    ; return

Getting the flag is only a matter of validating each condition, yielding you 1C4nR3adH3x.

> game2 1C4nR3adH3x                                                   
Here is my password checking function. Have fun !                     
3641008202003c19979859920206a2a061a79954a202073b99979a50a20209920205979a4b2ba8a7994a9202023b8887994692020a82a0788799419202084c8887993d8202014c39979839a202032cd9909830909074979a2f220204fb8887122b0c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c121df0
Success : Here is a cheat code 88c909 

There are at least 7 other flags to find in the badge, maybe I'll write about them if/when I take the time to get a dump of the firmware.

A laziest way to do it would be to use ESIL, by initializing the ESIL virtual machine with aeim, running until the first jump with aecu (as in Analysis with ESIL to Continue Until), and to check the corresponding register value:

jvoisin@kaa 16:48 ~ r2 -a xtensa -b 32 -
[0x00000000]> wx 3641008202003c19979859920206a2a061a79954a202073b99979a50a20209920205979a4b2ba8a7994a9202023b8887994692020a82a0788799419202084c8887993d8202014c39979839a202032cd9909830909074979a2f220204fb8887122b0c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c021df00c121df0
[0x00000000]> pd 8
            0x00000000      364100         entry a1, 32
            0x00000003      820200         l8ui a8, a2, 0
            0x00000006      3c19           movi.n a9, 49
        ┌─< 0x00000008      979859         bne a8, a9, 0x00000065
           0x0000000b      920206         l8ui a9, a2, 6
           0x0000000e      a2a061         movi a10, 97
       ┌──< 0x00000011      a79954         bne a9, a10, 0x00000069
       ││   0x00000014      a20207         l8ui a10, a2, 7
[0x00000000]> aeim
[0x00000000]> aecu 0x00000008
[0x00000000]> pdi 1 @ 0x00000008
0x00000008               979859  bne a8, a9, 0x00000065
[0x00000000]> ? a9
49 0x31 061 49 0000:0031 49 "1" 00110001 49.0 49.000000f 49.000000
[0x00000000]>

So as expected, the first letter is 1. You can get the other ones by manually setting registers with aer pc = 0x1337 or aer a9 = 0x1338 if you're too loafer to start over upon each good letter.