ご無沙汰してます。みむらです。
今年は、某「みかか」な場所で 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 でやってるんですよね。
うーんやっぱりやらないとなぁ。
みむらさんお久しぶりです!
メールの方にメッセージ送りましたのでお時間あるとき見てくれるとうれしいです。