English: Link
서버에 접속하면 레지스터의 값들과 이상한 문자열이 주어집니다.
오는 문자열을 hex encode해보면 모두 c3으로 끝나는데, 이는 x64에서 retq 명령어입니다. 따라서 저 assembly코드를 실행한 뒤, 레지스터의 값들을 같은 형태로 반환해주면 됩니다.
python으로 어셈블리어를 실행하기는 힘드므로 python으로 socket통신을 해서 레지스터 초기값을 받은 뒤 subprocess를 이용해 C언어로 컴파일한 바이너리를 이용합시다.
C에서
register unsigned long long rax asm("rax");
로 rax변수를 선언하면 rax 레지스터의 값에 접근할 수 있습니다.
전해받은 assembly어를 code배열에 넣은 뒤 이를 실행합시다.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
void (*f)();
register unsigned long long rax asm("rax");
register unsigned long long rbx asm("rbx");
register unsigned long long rcx asm("rcx");
register unsigned long long rdx asm("rdx");
register unsigned long long rsi asm("rsi");
register unsigned long long rdi asm("rdi");
register unsigned long long r8 asm("r8");
register unsigned long long r9 asm("r9");
register unsigned long long r10 asm("r10");
register unsigned long long r11 asm("r11");
register unsigned long long r12 asm("r12");
register unsigned long long r13 asm("r13");
register unsigned long long r14 asm("r14");
register unsigned long long r15 asm("r15");
unsigned long long _rax=0,_rbx=0,_rcx=0,_rdx=0,_rsi=0,_rdi=0,_r8=0,_r9=0,_r10=0,_r11=0,_r12=0,_r13=0,_r14=0,_r15=0;
unsigned char code[1024]={0,};
unsigned char tmp[3]={0,};
int tmp2=0;
if(argc<17) { printf("nope\n"); return 0; }
int i;
// hex encode된 명령어 code에 넣기
for(i=0; i<atoi(argv[1]); i++) {
memcpy(tmp, argv[16]+i*2, 2);
tmp2=strtol(tmp, &tmp, 16);
code[i]=tmp2;
}
_rax =strtoll(argv[2], 0, 16);
_rbx =strtoll(argv[3], 0, 16);
_rcx =strtoll(argv[4], 0, 16);
_rdx =strtoll(argv[5], 0, 16);
_rsi =strtoll(argv[6], 0, 16);
_rdi =strtoll(argv[7], 0, 16);
_r8 =strtoll(argv[8], 0, 16);
_r9 =strtoll(argv[9], 0, 16);
_r10=strtoll(argv[10], 0, 16);
_r11=strtoll(argv[11], 0, 16);
_r12=strtoll(argv[12], 0, 16);
_r13=strtoll(argv[13], 0, 16);
_r14=strtoll(argv[14], 0, 16);
_r15=strtoll(argv[15], 0, 16);
f=(void *)code;
rax=_rax;rbx=_rbx;rcx=_rcx;rdx=_rdx;
rsi=_rsi;rdi=_rdi;r8=_r8;r9=_r9;
r10=_r10;r11=_r11;r12=_r12;r13=_r13;
r14=_r14;r15=_r15;
// f의 위치: rbp-0xb8
asm volatile(
"call -0xb8(%rbp)\n\t"
);
_rax=rax;_rbx=rbx;_rcx=rcx;_rdx=rdx;
_rsi=rsi;_rdi=rdi;_r8=r8;_r9=r9;
_r10=r10;_r11=r11;_r12=r12;_r13=r13;
_r14=r14;_r15=r15;
printf("rax=0x%llx\n", _rax);
printf("rbx=0x%llx\n", _rbx);
printf("rcx=0x%llx\n", _rcx);
printf("rdx=0x%llx\n", _rdx);
printf("rsi=0x%llx\n", _rsi);
printf("rdi=0x%llx\n", _rdi);
printf("r8=0x%llx\n", _r8);
printf("r9=0x%llx\n", _r9);
printf("r10=0x%llx\n", _r10);
printf("r11=0x%llx\n", _r11);
printf("r12=0x%llx\n", _r12);
printf("r13=0x%llx\n", _r13);
printf("r14=0x%llx\n", _r14);
printf("r15=0x%llx", _r15);
return 0;
}
여기서 f()로 호출하면 컴파일러가 rax에 f의 주소를 넣고 call *%rax의 형태로 바뀌어서 rax값을 보존하기 위해 call 어셈블리를 inline으로 직접 넣었습니다. rbp-0xb8은 한번 컴파일을 해본 뒤 f가 어디에있는지 직접 찾아서 넣은 것입니다. f를 직접 호출하려고했는데 inline assembly와 C언어 변수간의 호환이 어렵더군요...
컴파일 할 때는 stack을 실행해야하므로 다음과같이 컴파일합니다.
gcc -o catwestern catwestern.c -z execstack -fno-stack-protector -g
그런 뒤 python wrapper로 인자를 맞춰서 전달해주면 됩니다.
from socket import *
s = socket(2,1)
s.connect(('catwestern_631d7907670909fc4df2defc13f2057c.quals.shallweplayaga.me',9999))
reg = s.recv(2048)
print reg
reg = reg.split('\n')[1:]
for i in reg:
exec i
a = s.recv(2048)
print a
a = a.split('\n')
a = '\n'.join(a[2:])
print 'LENGTH:', len(a)
regs = [rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12,r13,r14,r15]
for n,i in enumerate(regs):
if i>0x7fffffffffffffff:
regs[n] = -(0xffffffffffffffff-i+1)
cmd=('./catwestern %d ' +'%x '*14+ '%s')%(len(a),
regs[0],regs[1],regs[2],regs[3],regs[4],
regs[5],regs[6],regs[7],regs[8],regs[9],
regs[10],regs[11],regs[12],regs[13],a.encode('hex'))
import subprocess
print cmd
t = subprocess.check_output(cmd, shell=True)
for i in t.split('\n'):
exec i
ans = '''rax=0x%x
rbx=0x%x
rcx=0x%x
rdx=0x%x
rsi=0x%x
rdi=0x%x
r8=0x%x
r9=0x%x
r10=0x%x
r11=0x%x
r12=0x%x
r13=0x%x
r14=0x%x
r15=0x%x
''' % (rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12,r13,r14,r15)
print ans
s.send(ans)
print s.recv(2048)
Flag: Cats with frickin lazer beamz on top of their heads!
'CTF' 카테고리의 다른 글
Defcon23 (2015) babyecho (baby's first 1) writeup (KR) (0) | 2015.05.20 |
---|---|
Defcon23 (2015) catwestern (coding 1) writeup (EN) (0) | 2015.05.20 |
Defcon23 (2015) blackbox (misc 2) writeup (EN) (0) | 2015.05.18 |
Defcon23 (2015) blackbox (misc 2) writeup (KR) (0) | 2015.05.18 |
PlaidCTF 2015 Strength (crypto110) writeup (0) | 2015.04.20 |