A bit off
Published in

A bit off

Challenge Screenshot

Practical Binary Analysis: Ch 05 Challenge lvl5

Continuing with the challenges in Chapter 5, Practical Binary Analysis from Dennis Andriesse. Goal is to find a flag that would let us to open the next challenge while techniques being explained so far into the book are applied.

All levels start with a file, and in this case it’s another executable file that we have for level file. Execute the challenge:

binary@binary-VirtualBox:~/code/chapter5/level5$ ./lvl5
nothing to see here

That was not that useful no? Using previous level flag and getting some hints this is what we see:

binary@binary-VirtualBox:~/code/chapter5$ ./oracle 656cf8aecb76113a4dece1688c61d0e7 -h
Secrets hidden in code unused
The method of redirection is the key
Static rather than dynamically

Now we know that most of the binary analysis we’ll have to make is static, and that some how we’ll have to change program execution to give us the flag. Let’s see what else can we find.

binary@binary-VirtualBox:~/code/chapter5/level5$ strings lvl5 | more
/lib64/ld-linux-x86-64.so.2
libc.so.6
__printf_chk
puts
__stack_chk_fail
__libc_start_main
__gmon_start__
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.2.5
UH-H
D$(1
Eev4A6ufH
3peH
gqfH
T$ H
L$(dH3
AWAVA
AUATL
[]A\A]A^A_
key = 0x%08x
decrypted flag = %s
nothing to see here

;*3$"
...

Running strings on the program shows that there are two of them that we might be interested and refereed to the key, and the flag. Now we’ll have to figure out how to get to them.

We can trace program execution as is, and figure out if we have any helpful information:

binary@binary-VirtualBox:~/code/chapter5/level5$ ltrace -i ./lvl5
[0x400549] __libc_start_main(0x400500, 1, 0x7fff14981e98, 0x4006f0 <unfinished ...>
[0x40050e] puts("nothing to see here"nothing to see here
) = 20
[0xffffffffffffffff] +++ exited (status 1) +++
binary@binary-VirtualBox:~/code/chapter5/level5$

After using objdump to get the full dump of the binary we can take a look, what’s being executed it’s is:

0000000000400500 <.text>:
400500: 48 83 ec 08 sub rsp,0x8
400504: bf 97 07 40 00 mov edi,0x400797
400509: e8 a2 ff ff ff call 4004b0 <puts@plt>
40050e: b8 01 00 00 00 mov eax,0x1
400513: 48 83 c4 08 add rsp,0x8
400517: c3 ret
400518: 0f 1f 84 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
40051f: 00
400520: 31 ed xor ebp,ebp
400522: 49 89 d1 mov r9,rdx
400525: 5e pop rsi
400526: 48 89 e2 mov rdx,rsp
400529: 48 83 e4 f0 and rsp,0xfffffffffffffff0
40052d: 50 push rax
40052e: 54 push rsp
40052f: 49 c7 c0 60 07 40 00 mov r8,0x400760
400536: 48 c7 c1 f0 06 40 00 mov rcx,0x4006f0
40053d: 48 c7 c7 00 05 40 00 mov rdi,0x400500
400544: e8 87 ff ff ff call 4004d0 <__libc_start_main@plt>
400549: f4 hlt

The block of code that starts at 0x4500 it’s pretty simple, prints out the string we’re seeing on the string. There are big pieces of unused code in .text, so we’ll have to read a bit through it.

We know that the challenge will use the strings we got before when printing, and maybe looking into any functions it might be using for printing that content would be useful for us. Let’s take a look at what other information we can collect.

binary@binary-VirtualBox:~/code/chapter5/level5$ nm -D lvl5
w __gmon_start__
U __libc_start_main
U __printf_chk
U puts
U __stack_chk_fail

One way that I did proceed on this exercise was looking at the strings being used, and the ones we found earlier. Firing up the binary with gdb, and looking stepping to the functions there is one thing I tried to figure out.

binary@binary-VirtualBox:~/code/chapter5/level5$ gdb lvl5
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
...
(gdb) set disassembly-flavor intel
(gdb) b *0x400544
Breakpoint 1 at 0x400544
(gdb) b *0x400500
Breakpoint 2 at 0x400500
(gdb) r
Starting program: /home/binary/code/chapter5/level5/lvl5
Breakpoint 1, 0x0000000000400544 in ?? ()
(gdb) c
Continuing.
Breakpoint 2, 0x0000000000400500 in ?? ()
(gdb) ni
0x0000000000400504 in ?? ()
(gdb) ni
(gdb) x/i $rip
=> 0x400504: mov edi,0x400797
(gdb) x/s $edi
0x400797: "nothing to see here"
(gdb) x/10s 0x400797 - 0x25
0x400772: "\002"
0x400774: "key = 0x%08x\n"
0x400782: "decrypted flag = %s\n"
0x400797: "nothing to see here"
0x4007ab: ""
0x4007ac: "\001\033\003;@"
0x4007b2: ""
0x4007b3: ""
0x4007b4: "\a"
0x4007b6: ""

At 0x400504 we see that the memory address to the string `nothing to see here` is being referenced, so looking a little backwards into that memory address we might be able to see the rest of them. Now we this in mind, we can look into the disassembly of the binary if the other two (0x400774 and 0x400782) are being referenced. Here is where I found them:

  400620:       53                      push   rbx
400621: be 74 07 40 00 mov esi,0x400774
400626: bf 01 00 00 00 mov edi,0x1
40062b: 48 83 ec 30 sub rsp,0x30
40062f: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28
400636: 00 00
400638: 48 89 44 24 28 mov QWORD PTR [rsp+0x28],rax
40063d: 31 c0 xor eax,eax
40063f: 48 b8 10 60 21 33 15 movabs rax,0x6223331533216010
400646: 33 23 62
400649: c6 44 24 20 00 mov BYTE PTR [rsp+0x20],0x0
40064e: 48 89 04 24 mov QWORD PTR [rsp],rax
400652: 48 b8 45 65 76 34 41 movabs rax,0x6675364134766545
400659: 36 75 66
40065c: 48 89 44 24 08 mov QWORD PTR [rsp+0x8],rax
400661: 48 b8 17 67 75 64 10 movabs rax,0x6570331064756717
400668: 33 70 65
40066b: 48 89 44 24 10 mov QWORD PTR [rsp+0x10],rax
400670: 48 b8 18 35 76 62 11 movabs rax,0x6671671162763518
400677: 67 71 66
40067a: 48 89 44 24 18 mov QWORD PTR [rsp+0x18],rax
40067f: 8b 1c 25 40 05 40 00 mov ebx,DWORD PTR ds:0x400540
400686: 31 c0 xor eax,eax
400688: 89 da mov edx,ebx
40068a: e8 51 fe ff ff call 4004e0 <__printf_chk@plt>
40068f: 48 8d 54 24 20 lea rdx,[rsp+0x20]
400694: 48 89 e0 mov rax,rsp
400697: 66 0f 1f 84 00 00 00 nop WORD PTR [rax+rax*1+0x0]
40069e: 00 00
4006a0: 31 18 xor DWORD PTR [rax],ebx
4006a2: 48 83 c0 04 add rax,0x4
4006a6: 48 39 d0 cmp rax,rdx
4006a9: 75 f5 jne 4006a0 <__printf_chk@plt+0x1c0>
4006ab: 31 c0 xor eax,eax
4006ad: 48 89 e2 mov rdx,rsp
4006b0: be 82 07 40 00 mov esi,0x400782
4006b5: bf 01 00 00 00 mov edi,0x1
4006ba: e8 21 fe ff ff call 4004e0 <__printf_chk@plt>
4006bf: 31 c0 xor eax,eax
4006c1: 48 8b 4c 24 28 mov rcx,QWORD PTR [rsp+0x28]
4006c6: 64 48 33 0c 25 28 00 xor rcx,QWORD PTR fs:0x28
4006cd: 00 00

If we set any breakpoint in this section of code it would never be executed, so we need to find a way to redirect the execution flow here. At 0x40053d we see that the start of the function is being passed to __libc_start_main, so we can replace that with the address we want:

(gdb) r
Starting program: /home/binary/code/chapter5/level5/lvl5
Breakpoint 1, 0x0000000000400544 in ?? ()
(gdb) x/10i $rip - 0x15
0x40052f: mov r8,0x400760
0x400536: mov rcx,0x4006f0
0x40053d: mov rdi,0x400500
=> 0x400544: call 0x4004d0 <__libc_start_main@plt>
0x400549: hlt
0x40054a: nop WORD PTR [rax+rax*1+0x0]
0x400550: mov eax,0x60104f
0x400555: push rbp
0x400556: sub rax,0x601048
0x40055c: cmp rax,0xe
(gdb) set $rdi = 0x400620
(gdb) x/10i $rip
=> 0x400620: push rbx
0x400621: mov esi,0x400774
0x400626: mov edi,0x1
0x40062b: sub rsp,0x30
0x40062f: mov rax,QWORD PTR fs:0x28
0x400638: mov QWORD PTR [rsp+0x28],rax
0x40063d: xor eax,eax
0x40063f: movabs rax,0x6223331533216010
0x400649: mov BYTE PTR [rsp+0x20],0x0
0x40064e: mov QWORD PTR [rsp],rax
(gdb) c
Continuing.
key = 0x00400500
decrypted flag = ea36cbE`64A35fb5d60e06bb1f
[Inferior 1 (process 29664) exited normally]

Now it does seems we’re getting somewhere, but still the flag does not seems valid, that could mean we have an incorrect key. A deeper look into the function we’re not executing could int us where the flag seems to be decoded and how they key is actually used.

  400694:       48 89 e0                mov    rax,rsp
400697: 66 0f 1f 84 00 00 00 nop WORD PTR [rax+rax*1+0x0]
40069e: 00 00
4006a0: 31 18 xor DWORD PTR [rax],ebx
4006a2: 48 83 c0 04 add rax,0x4
4006a6: 48 39 d0 cmp rax,rdx
4006a9: 75 f5 jne 4006a0 <__printf_chk@plt+0x1c0>

At 0x400694 the encoded flag pointed by rax and then there is a loop xoring each byte with the content of ebx. The value that’s being stored in ebx is 0x48, which is loaded at 0x40067f. It points to 0x00400500

One of the hints is that The method of redirection is the key , so if we wanted to point the execution of the binary to the address that would print the key, we could try to rewrite that value and patch the binary as we’ve done before.

We can use xxd to dump the challenge contents and then look for the sequence of bytes we need to replace 48 c7 c7 00 05 40 00 :

00000500: 4883 ec08 bf97 0740 00e8 a2ff ffff b801  H......@........
00000510: 0000 0048 83c4 08c3 0f1f 8400 0000 0000 ...H............
00000520: 31ed 4989 d15e 4889 e248 83e4 f050 5449 1.I..^H..H...PTI
00000530: c7c0 6007 4000 48c7 c1f0 0640 0048 c7c7 ..`.@.H....@.H..
00000540: 0005 4000 e887 ffff fff4 660f 1f44 0000 ..@.......f..D..
00000550: b84f 1060 0055 482d 4810 6000 4883 f80e .O.`.UH-H.`.H...
00000560: 4889 e576 1bb8 0000 0000 4885 c074 115d H..v......H..t.]

We correct the address, patch the binary and now we can validate our patch with object dump, it should looks similar

  40052f:       49 c7 c0 60 07 40 00    mov    r8,0x400760
400536: 48 c7 c1 f0 06 40 00 mov rcx,0x4006f0
40053d: 48 c7 c7 20 06 40 00 mov rdi,0x400620
400544: e8 87 ff ff ff call 4004d0 <__libc_start_main@plt>

For confirming this value we can use gdb again:

binary@binary-VirtualBox:~/code/chapter5/level5$ gdb fixed

(gdb) set disassembly-flavor intel
(gdb) b *0x4006a0
Breakpoint 1 at 0x4006a0
(gdb) r
Starting program: /home/binary/code/chapter5/level5/fixed
key = 0x00400620
Breakpoint 1, 0x00000000004006a0 in ?? ()
(gdb) x/10i $rip
=> 0x4006a0: xor DWORD PTR [rax],ebx
0x4006a2: add rax,0x4
0x4006a6: cmp rax,rdx
0x4006a9: jne 0x4006a0
0x4006ab: xor eax,eax
0x4006ad: mov rdx,rsp
0x4006b0: mov esi,0x400782
0x4006b5: mov edi,0x1
0x4006ba: call 0x4004e0 <__printf_chk@plt>
0x4006bf: xor eax,eax
(gdb) x/x $ebx
0x400620: 0x53
(gdb) del breakpoints 1
(gdb) c
Continuing.
decrypted flag = 0fa355cbec64a05f7a5d050e836b1a1f
[Inferior 1 (process 29928) exited normally]

By looking at this we can see that the xor value is the byte located at 0x400620: 400620: 53 push rbx . Now we pass the flag to unlock the next level:

binary@binary-VirtualBox:~/code/chapter5$ ./oracle 0fa355cbec64a05f7a5d050e836b1a1f
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Level 5 completed, unlocked lvl6 |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
Run oracle with -h to show a hint

And now we can move along to the next level.

--

--

--

A little bit of everything cybersecurity related. Experiments, tutorials and challenges

Recommended from Medium

Build a Netflix API Miner With Python

Preparation and passing the AWS Solution Architect (SCAA-01) — Associate exam on the first attempt

An Introduction to Functions in Heap

AI Platform Notebooks with Voila

Navigating My First Tech Conference

Soccer Microservice on ASP.NET, Entity Framework, Mysql and Insomnia.

Top 3 Resources to Master Python in 2021

Demystifying Quality Assurance

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Pablo Ramos

Pablo Ramos

Infosec Researcher, traveller, kitesurfing enthusiast. I just like to think outloud

More from Medium

Vulnversity Walkthrough — THM

TryHackMe: Nmap Advanced Port Scans Walkthrough

Nmap Advanced Port Scans Room’s logo at TryHackMe

Snooping credentials through Net-NTLMv2 | HashCat Cracking

picoCTF 2022 bloat.py writeup