DEFCON CTF 23 Quals」タグアーカイブ

DEFCON CTF 23 Quals – catwestern Writeup

ご無沙汰してます。みむらです。
今年は、某「みかか」な場所で Team Enu のみなさんと一緒に参加してきました。

やはり合宿形式でやるというのは面白いですし、
出来る人が周りに居ますと、それだけでかなり成長できるなということを強く思いました。
・・・来年もこういう感じで出来たらいいなぁ・・と思うそんな今日この頃です。

というわけで、ちゃんと最後まで自分でやりきった内容の Write-up ということで
catwestern のWrite-up を。

 

catwestern


指定されたサーバに接続すると次のようなバイナリデータが送信されてきます。

image

 

上の方は「レジスタ」の情報で、
”About to send ** bytes:” の先に x86_64 っぽいバイナリが
送られてきていることがわかるかと思います。

 

ここで mzyy94 (みっきー)さんが
「rax=… をそのまま返すと、応答が変わる!」と教えてくれまして
実行してその結果を返せばいいのかな、ということでやってみました。

 

Code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/mman.h>
 
static char* code;
static unsigned long reg[15];
 
void main(void)
{
    int sock;
    struct sockaddr_in server;
 
    memset((void*)&server,0,sizeof(server));
    server.sin_addr.s_addr = inet_addr("52.74.101.145");
    server.sin_family = AF_INET;
    server.sin_port = htons(9999);
 
    sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock == -1) return;
 
    if(connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0)
        return;
 
    while(1)
    {
        char buf[4192];
        int i,codesize,pagesize;
 
        memset(buf,0,sizeof(buf));
        read(sock,buf,sizeof(buf));
 
        printf("INPUT : \n%s\n",buf);
 
        {
            char *tp;
         
            tp = strtok(buf,"\n");
            for(i = -1; tp != NULL; i++)
            {
                if(strstr(tp,"=") != 0)
                    reg[i] = strtouq(strstr(tp,"=")+1,NULL,0);
                tp = strtok(NULL,"\n");
            }
        }

        read(sock,buf,sizeof(buf));
        codesize = atoi(buf+0x37);
 
        if(codesize == 0)
            break;
 
        pagesize = sysconf(_SC_PAGE_SIZE);
        code = memalign(pagesize,pagesize);
 
        memset(code,0xC3,pagesize);
        memcpy(code,buf+0x42,codesize);
        printf("CODESIZE : %d bytes.\n",codesize);
 
        if(mprotect(code,pagesize,PROT_READ | PROT_EXEC) < 0)
        {
            free(code);
            return;
        }
 
        printf("EXECUTE..");
 
        asm volatile ("movq (reg),%rax");
        asm volatile ("movq (reg+8),%rbx");
        asm volatile ("movq (reg+16),%rcx");
        asm volatile ("movq (reg+24),%rdx");
        asm volatile ("movq (reg+32),%rsi");
        asm volatile ("movq (reg+40),%rdi");
        asm volatile ("movq (reg+48),%r8");
        asm volatile ("movq (reg+56),%r9");
        asm volatile ("movq (reg+64),%r10");
        asm volatile ("movq (reg+72),%r11");
        asm volatile ("movq (reg+80),%r12");
        asm volatile ("movq (reg+88),%r13");
        asm volatile ("movq (reg+96),%r14");
        asm volatile ("movq (reg+104),%r15");
         
        asm volatile ("call *code");
 
        asm volatile ("movq %rax,(reg)");
        asm volatile ("movq %rbx,(reg+8)");
        asm volatile ("movq %rcx,(reg+16)");
        asm volatile ("movq %rdx,(reg+24)");
        asm volatile ("movq %rsi,(reg+32)");
        asm volatile ("movq %rdi,(reg+40)");
        asm volatile ("movq %r8,(reg+48)");
        asm volatile ("movq %r9,(reg+56)");
        asm volatile ("movq %r10,(reg+64)");
        asm volatile ("movq %r11,(reg+72)");
        asm volatile ("movq %r12,(reg+80)");
        asm volatile ("movq %r13,(reg+88)");
        asm volatile ("movq %r14,(reg+96)");
        asm volatile ("movq %r15,(reg+104)");
         
        printf("DONE.\n");
        free(code);
 
        memset(buf,0,sizeof(buf));
        sprintf(buf,"rax=0x%llx\nrbx=0x%llx\nrcx=0x%llx\nrdx=0x%llx\nrsi=0x%llx\nrdi=0x%llx\nr8=0x%llx\nr9=0x%llx\nr10=0x%llx\nr11=0x%llx\nr12=0x%llx\nr13=0x%llx\nr14=0x%llx\nr15=0x%llx\n",reg[0],reg[1],reg[2],reg[3],reg[4],reg[5],reg[6],reg[7],reg[8],reg[9],reg[10],reg[11],reg[12],reg[13]);
 
        printf("OUTPUT :\n%s\n",buf);
        write(sock,buf,strlen(buf));
    }
}

 

内容としては、レジスタの初期値を持ってきて、

自分自身に対してその値を設定 → 実行 → レジスタの値を取得して送り返す。

という流れになります。

..そんな感じで実行しますと、

FLAG IS : Cats with frickin lazer beamz on top of their heads!

ということで返答が帰ってきますんで、これを送ると得点がえられました。

 


余談:

このあたりに後ろ姿が..

https://www.ntt.com/wideangle_security/data/sec_repo.html

また、今回こそは “Python コード書くぞ!!” と思っていたんですが、

気づいたら C と C# しか書いていませんでした。

(特に、「コード貼ってよ」→「C# ですがいいですか」→「C#… orz」 の流れは辛かったです)

次回こそは・・次回こそは・・!

(Babyecho も Pwn も C# で取り組んでました.  BitConverter.GetBytes() は偉大です.

…この問題の Write-up も、他の人はみんな通信部分は Python でやってるんですよね。

うーんやっぱりやらないとなぁ。