ご無沙汰してます。みむらです。
今年は、某「みかか」な場所で Team Enu のみなさんと一緒に参加してきました。
やはり合宿形式でやるというのは面白いですし、
出来る人が周りに居ますと、それだけでかなり成長できるなということを強く思いました。
・・・来年もこういう感じで出来たらいいなぁ・・と思うそんな今日この頃です。
というわけで、ちゃんと最後まで自分でやりきった内容の Write-up ということで
catwestern のWrite-up を。
catwestern
指定されたサーバに接続すると次のようなバイナリデータが送信されてきます。
上の方は「レジスタ」の情報で、
”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 でやってるんですよね。
うーんやっぱりやらないとなぁ。