ASIS-CTF-Quals-2014-Auth/Serial-number/Plough-Writeup

###Auth[reverse150]

说明:

The Server is running at the following address. file
87.107.124.12:25565

首先打开IDA,简单分析下发现程序监听25565端口,然后获得连接后开启新进程转入sub_401F9D函数。
sub_401F9D是关键的对输入审核的函数,比较复杂,如果过了其层层审核,最后会返回’YOU WIN!’.很明显,如果输入让程序走到这一步,那么服务器应该发送flag回来了。
显示两个简单的判断,要求第一步发送’hello’,第二步发送’send salt’.
1.png2.png
然后程序发送一个12字节的字符串,比如第一次就是’ NTU2NTYxNDM5’。而且每次程序发送的字符串都不相同。
接下来程序收到数据后call进sub_401AA3函数。这个函数有点复杂。
3.png
函数有6个参数sub_401AA3(buf, p1, p2, a3, p4, p5, a6)。简单来说,就是把输入的字符串按照#为分隔,复制到p1,p1+0x22,…,p2,p4,p5等地址上。
然后程序call进sub_401D86函数。这个函数首先把p1,p1+0x22,…,p2,p4,’ NTU2NTYxNDM5’格式化打印到一个地址(注意没有p5)。
4.png
然后对上述数据取sha1哈希值
5.png
是不是有点像pctf的哈希扩展攻击。。。
最终与p5对应的字符串比较
6.png
然后回到sub_401F9D函数后,对p1,p1+0x22,…等对应的字符串比较。如果都满足且整个过程的时间小于5秒的话,程序会回显‘YOU WIN!’
OK,清楚上述逻辑后,第三次发送的字符串将是
‘…’+#+’…’+#+’…’+……+#+sha1(‘…’+#+’…’+#+’…’+……+#)
脚本如下:

#coding:utf-8

import hashlib
import os
import time
from socket import *

s_send = 'quals_.#192.168..#asis_ctf##asis_.##' 
s_calc = 'quals_.#192.168..#asis_ctf##asis_.#'

hash_new = hashlib.sha1()

s = socket(AF_INET, SOCK_STREAM)

s.connect(('87.107.124.12', 25565))

print 'hello'
s.send('hello') 

print s.recv(1024)

print 'send salt'
s.send('send salt')

salt = s.recv(1024)
print salt

s_calc += salt

l = list(s_calc)
leng = len(l)

l = l[:leng-1]
s_calc = ''.join(l)
print 's_calc',s_calc
hash_new.update(s_calc)

s_send += hash_new.hexdigest()

print s_send
s.send(s_send)

print s.recv(1024)

###Serial number[reverse300]
说明:

(空)

这个看见主函数就吓尿了
7.png
仔细分析,发现程序首先分配了四处空间,地址放在rbp-28处。
8.png
然后要求十六进制格式输入,每次处理4bit。
9.png
然后操作太多了,就不细说了。最后会有一处根据前面的逻辑判断,改变刚开始分配的四处内存的值
10.png
等到所有输入处理完后,程序对rbp-14的地方判断,如果为1则输入正确,否则错误。
接着看,程序要求输入的4bit为1 1 0 1,而四处分配内存值为1 0 1 1是才会给rbp-14赋值为1
11.png
于是,按照程序逻辑,最后的输入为0xda34c5217f9d
12.png
###Plough[crypto250]
说明:

Source code of encryptor and encrypted file is given

加密程序给的是c++代码,代码就不贴了。分析下发现其加密逻辑是,首先把明文密文都看作二进制流,比如如果明文是’123’的话,就认为是
001100010011001000110011
然后,用密文前三比特表示明文从开始到第一个1出现前0的个数。那么密文开始三比特就是
010
然后密文后两比特表示之后1出现的个数,就是
10
然后又用三比特表示0出现的个数
011
以此类推,如果密文长度够八比特就输出一字节密文,所以密文的第一个字节就是
01010011 ==> 53
明白了其加密逻辑,解密就好弄了。C代码如下

#include<stdio.h>
#include<stdlib.h>

int     ocount;
unsigned char       oexp;

int     icount;
char        iexp;

unsigned char output(FILE *f, unsigned int bit, unsigned char value)
{
    unsigned char vvalue = 0;
    while(bit)
    {
        if(ocount == 8)
        {
            putc(oexp, f);
            ocount = 0;
            oexp = 0;
        }
        else
        {
            
            vvalue = (value > 0);
            vvalue <<= (7-ocount);
            oexp |= vvalue;
            ocount++;
            bit--;
        }
    }

    return 0;
}

unsigned char input(FILE *f, unsigned int bit)
{
    unsigned char chr = 0;

    while(bit)
    {
        if(icount)
        {
            chr <<= 1;
            chr |= (iexp & 0x80) >> 7;
            iexp <<= 1;
            icount--;
            
            bit--;
        }
        else
        {
            
            if( !feof(f) )
            {
                iexp = getc(f);
                icount = 8;
            }
            else
            {
                exit(0);
            }
        }

    }

    return chr;
}
int main()
{
    FILE *fin  = fopen("encrypted", "rb");
    FILE *fout = fopen("decoded.jpg", "wb");

    int i = 0;
    unsigned char chr = 0;

    while(1)
    {
        if(i)
        {
            //2,1
            chr = input(fin, 2);
            output(fout, chr, 1);
            i = 0;
        }
        else
        {
            //3,0
            chr = input(fin, 3);
            output(fout, chr, 0);
            i = 1;
        }
    }

    return 0;
}

解出来是一张图片
decoded.jpg

@Da2din9o ::TEAM L::

tagged by none  

Comment Closed.

© 2014 ::L Team::