此C程序中是否存在命令执行漏洞



因此,我正在处理一个难题,在C程序二进制文件中发现一个漏洞,该漏洞允许程序执行命令(在Linux中使用有效的UID(。

我真的很难找到如何用这个特殊的程序做到这一点。

有关功能(主要功能(的拆卸:


**************************************************************
*                                                            *
*  FUNCTION                                                  *
**************************************************************
int __cdecl main(int argc, char * * argv)
int               EAX:4          <RETURN>
int               Stack[0x4]:4   argc
char * *          Stack[0x8]:4   argv                            XREF[2]:     000109b0(R), 
             000109dd(R)  
undefined4        Stack[-0x8]:4  local_8                         XREF[1]:     00010bcb(R)  
int               Stack[-0xc]:4  in                              XREF[5]:     000109f0(W), 
             000109f3(R), 
             00010ad4(R), 
             00010b27(R), 
             00010b59(R)  
int               Stack[-0x10]:4 fd                              XREF[6]:     00010a1f(W), 
             00010a22(R), 
             00010aa5(R), 
             00010ab2(R), 
             00010ac9(R), 
             00010b4e(R)  
pid_t             Stack[-0x14]:4 pid                             XREF[4]:     00010a6b(W), 
             00010a6e(R), 
             00010a8b(R), 
             00010b6a(R)  
int[2]            Stack[-0x1c]:8 pipefd                          XREF[3,3]:   00010a3f(*), 
             00010a95(R), 
             00010b42(R), 
             00010abd(R), 
             00010b0f(R), 
             00010b36(R)  
char              Stack[-0x1d]:1 c                               XREF[2]:     00010b14(*), 
             00010b23(*)  
int               Stack[-0x24]:4 status                          XREF[2]:     00010b66(*), 
             00010b75(R)  
main                                    XREF[5]:     Entry Point(*), 
    _start:00010866(*), 00010d30, 
            00010da0(*), 00011f34(*)  
0001097d 55              PUSH       EBP
0001097e 89 e5           MOV        EBP,ESP
00010980 53              PUSH       EBX
00010981 83 ec 1c        SUB        ESP,0x1c
00010984 e8 87 16        CALL       <EXTERNAL>::geteuid                              __uid_t geteuid(void)
00 00
00010989 89 c3           MOV        EBX,EAX
0001098b e8 80 16        CALL       <EXTERNAL>::geteuid                              __uid_t geteuid(void)
00 00
00010990 53              PUSH       EBX
00010991 50              PUSH       EAX
00010992 e8 9d 16        CALL       <EXTERNAL>::setreuid                             int setreuid(__uid_t __ruid, __u
00 00
00010997 83 c4 08        ADD        ESP,0x8
0001099a e8 75 16        CALL       <EXTERNAL>::getegid                              __gid_t getegid(void)
00 00
0001099f 89 c3           MOV        EBX,EAX
000109a1 e8 6e 16        CALL       <EXTERNAL>::getegid                              __gid_t getegid(void)
00 00
000109a6 53              PUSH       EBX
000109a7 50              PUSH       EAX
000109a8 e8 9b 16        CALL       <EXTERNAL>::setregid                             int setregid(__gid_t __rgid, __g
00 00
000109ad 83 c4 08        ADD        ESP,0x8
000109b0 8b 45 0c        MOV        EAX,dword ptr [EBP + argv]
000109b3 83 c0 04        ADD        EAX,0x4
000109b6 8b 00           MOV        EAX,dword ptr [EAX]
000109b8 85 c0           TEST       EAX,EAX
000109ba 75 21           JNZ        LAB_000109dd
000109bc a1 98 1f        MOV        EAX,[stderr]
01 00
000109c1 50              PUSH       EAX
000109c2 6a 22           PUSH       0x22
000109c4 6a 01           PUSH       0x1
000109c6 68 50 0c        PUSH       s_Please_specify_the_file_to_verif_00010c50      = "Please specify the file to ve
01 00
000109cb e8 50 16        CALL       <EXTERNAL>::fwrite                               size_t fwrite(void * __ptr, size
00 00
000109d0 83 c4 10        ADD        ESP,0x10
000109d3 b8 01 00        MOV        EAX,0x1
00 00
000109d8 e9 ee 01        JMP        LAB_00010bcb
00 00
LAB_000109dd                                    XREF[1]:     000109ba(j)  
000109dd 8b 45 0c        MOV        EAX,dword ptr [EBP + argv]
000109e0 83 c0 04        ADD        EAX,0x4
000109e3 8b 00           MOV        EAX,dword ptr [EAX]
000109e5 6a 00           PUSH       0x0
000109e7 50              PUSH       EAX
000109e8 e8 43 16        CALL       <EXTERNAL>::open                                 int open(char * __file, int __of
00 00
000109ed 83 c4 08        ADD        ESP,0x8
000109f0 89 45 f8        MOV        dword ptr [EBP + in],EAX
000109f3 83 7d f8 00     CMP        dword ptr [EBP + in],0x0
000109f7 79 17           JNS        LAB_00010a10
000109f9 68 73 0c        PUSH       DAT_00010c73                                     = 6Fh    o
01 00
000109fe e8 19 16        CALL       <EXTERNAL>::perror                               void perror(char * __s)
00 00
00010a03 83 c4 04        ADD        ESP,0x4
00010a06 b8 02 00        MOV        EAX,0x2
00 00
00010a0b e9 bb 01        JMP        LAB_00010bcb
00 00
LAB_00010a10                                    XREF[1]:     000109f7(j)  
00010a10 6a 02           PUSH       0x2
00010a12 68 78 0c        PUSH       s_/dev/null_00010c78                             = "/dev/null"
01 00
00010a17 e8 14 16        CALL       <EXTERNAL>::open                                 int open(char * __file, int __of
00 00
00010a1c 83 c4 08        ADD        ESP,0x8
00010a1f 89 45 f4        MOV        dword ptr [EBP + fd],EAX
00010a22 83 7d f4 00     CMP        dword ptr [EBP + fd],0x0
00010a26 79 17           JNS        LAB_00010a3f
00010a28 68 73 0c        PUSH       DAT_00010c73                                     = 6Fh    o
01 00
00010a2d e8 ea 15        CALL       <EXTERNAL>::perror                               void perror(char * __s)
00 00
00010a32 83 c4 04        ADD        ESP,0x4
00010a35 b8 05 00        MOV        EAX,0x5
00 00
00010a3a e9 8c 01        JMP        LAB_00010bcb
00 00
LAB_00010a3f                                    XREF[1]:     00010a26(j)  
00010a3f 8d 45 e8        LEA        EAX=>pipefd,[EBP + -0x18]
00010a42 50              PUSH       EAX
00010a43 e8 f8 15        CALL       <EXTERNAL>::pipe                                 int pipe(int * __pipedes)
00 00
00010a48 83 c4 04        ADD        ESP,0x4
00010a4b 85 c0           TEST       EAX,EAX
00010a4d 79 17           JNS        LAB_00010a66
00010a4f 68 82 0c        PUSH       DAT_00010c82                                     = 70h    p
01 00
00010a54 e8 c3 15        CALL       <EXTERNAL>::perror                               void perror(char * __s)
00 00
00010a59 83 c4 04        ADD        ESP,0x4
00010a5c b8 03 00        MOV        EAX,0x3
00 00
00010a61 e9 65 01        JMP        LAB_00010bcb
00 00
LAB_00010a66                                    XREF[1]:     00010a4d(j)  
00010a66 e8 d9 15        CALL       <EXTERNAL>::fork                                 __pid_t fork(void)
00 00
00010a6b 89 45 f0        MOV        dword ptr [EBP + pid],EAX
00010a6e 83 7d f0 00     CMP        dword ptr [EBP + pid],0x0
00010a72 79 17           JNS        LAB_00010a8b
00010a74 68 87 0c        PUSH       DAT_00010c87                                     = 66h    f
01 00
00010a79 e8 9e 15        CALL       <EXTERNAL>::perror                               void perror(char * __s)
00 00
00010a7e 83 c4 04        ADD        ESP,0x4
00010a81 b8 04 00        MOV        EAX,0x4
00 00
00010a86 e9 40 01        JMP        LAB_00010bcb
00 00
LAB_00010a8b                                    XREF[1]:     00010a72(j)  
00010a8b 83 7d f0 00     CMP        dword ptr [EBP + pid],0x0
00010a8f 0f 85 8c        JNZ        LAB_00010b21
00 00 00
00010a95 8b 45 e8        MOV        EAX,dword ptr [EBP + pipefd[0]]
00010a98 6a 00           PUSH       0x0
00010a9a 50              PUSH       EAX
00010a9b e8 60 15        CALL       <EXTERNAL>::dup2                                 int dup2(int __fd, int __fd2)
00 00
00010aa0 83 c4 08        ADD        ESP,0x8
00010aa3 6a 01           PUSH       0x1
00010aa5 ff 75 f4        PUSH       dword ptr [EBP + fd]
00010aa8 e8 53 15        CALL       <EXTERNAL>::dup2                                 int dup2(int __fd, int __fd2)
00 00
00010aad 83 c4 08        ADD        ESP,0x8
00010ab0 6a 02           PUSH       0x2
00010ab2 ff 75 f4        PUSH       dword ptr [EBP + fd]
00010ab5 e8 46 15        CALL       <EXTERNAL>::dup2                                 int dup2(int __fd, int __fd2)
00 00
00010aba 83 c4 08        ADD        ESP,0x8
00010abd 8b 45 ec        MOV        EAX,dword ptr [EBP + pipefd[1]]
00010ac0 50              PUSH       EAX
00010ac1 e8 8a 15        CALL       <EXTERNAL>::close                                int close(int __fd)
00 00
00010ac6 83 c4 04        ADD        ESP,0x4
00010ac9 ff 75 f4        PUSH       dword ptr [EBP + fd]
00010acc e8 7f 15        CALL       <EXTERNAL>::close                                int close(int __fd)
00 00
00010ad1 83 c4 04        ADD        ESP,0x4
00010ad4 ff 75 f8        PUSH       dword ptr [EBP + in]
00010ad7 e8 74 15        CALL       <EXTERNAL>::close                                int close(int __fd)
00 00
00010adc 83 c4 04        ADD        ESP,0x4
00010adf 6a 00           PUSH       0x0
00010ae1 68 8c 0c        PUSH       s_-asxml_00010c8c                                = "-asxml"
01 00
00010ae6 68 93 0c        PUSH       DAT_00010c93                                     = 74h    t
01 00
00010aeb 68 93 0c        PUSH       DAT_00010c93                                     = 74h    t
01 00
00010af0 e8 17 15        CALL       <EXTERNAL>::execlp                               int execlp(char * __file, char *
00 00
00010af5 83 c4 10        ADD        ESP,0x10
00010af8 68 98 0c        PUSH       s_execlp_00010c98                                = "execlp"
01 00
00010afd e8 1a 15        CALL       <EXTERNAL>::perror                               void perror(char * __s)
00 00
00010b02 83 c4 04        ADD        ESP,0x4
00010b05 b8 05 00        MOV        EAX,0x5
00 00
00010b0a e9 bc 00        JMP        LAB_00010bcb
00 00
LAB_00010b0f                                    XREF[1]:     00010b34(j)  
00010b0f 8b 45 ec        MOV        EAX,dword ptr [EBP + pipefd[1]]
00010b12 6a 01           PUSH       0x1
00010b14 8d 55 e7        LEA        EDX=>c,[EBP + -0x19]
00010b17 52              PUSH       EDX
00010b18 50              PUSH       EAX
00010b19 e8 1e 15        CALL       <EXTERNAL>::write                                ssize_t write(int __fd, void * _
00 00
00010b1e 83 c4 0c        ADD        ESP,0xc
LAB_00010b21                                    XREF[1]:     00010a8f(j)  
00010b21 6a 01           PUSH       0x1
00010b23 8d 45 e7        LEA        EAX=>c,[EBP + -0x19]
00010b26 50              PUSH       EAX
00010b27 ff 75 f8        PUSH       dword ptr [EBP + in]
00010b2a e8 d5 14        CALL       <EXTERNAL>::read                                 ssize_t read(int __fd, void * __
00 00
00010b2f 83 c4 0c        ADD        ESP,0xc
00010b32 85 c0           TEST       EAX,EAX
00010b34 75 d9           JNZ        LAB_00010b0f
00010b36 8b 45 ec        MOV        EAX,dword ptr [EBP + pipefd[1]]
00010b39 50              PUSH       EAX
00010b3a e8 11 15        CALL       <EXTERNAL>::close                                int close(int __fd)
00 00
00010b3f 83 c4 04        ADD        ESP,0x4
00010b42 8b 45 e8        MOV        EAX,dword ptr [EBP + pipefd[0]]
00010b45 50              PUSH       EAX
00010b46 e8 05 15        CALL       <EXTERNAL>::close                                int close(int __fd)
00 00
00010b4b 83 c4 04        ADD        ESP,0x4
00010b4e ff 75 f4        PUSH       dword ptr [EBP + fd]
00010b51 e8 fa 14        CALL       <EXTERNAL>::close                                int close(int __fd)
00 00
00010b56 83 c4 04        ADD        ESP,0x4
00010b59 ff 75 f8        PUSH       dword ptr [EBP + in]
00010b5c e8 ef 14        CALL       <EXTERNAL>::close                                int close(int __fd)
00 00
00010b61 83 c4 04        ADD        ESP,0x4
00010b64 6a 00           PUSH       0x0
00010b66 8d 45 e0        LEA        EAX=>status,[EBP + -0x20]
00010b69 50              PUSH       EAX
00010b6a ff 75 f0        PUSH       dword ptr [EBP + pid]
00010b6d e8 b2 14        CALL       <EXTERNAL>::waitpid                              __pid_t waitpid(__pid_t __pid, i
00 00
00010b72 83 c4 0c        ADD        ESP,0xc
00010b75 8b 45 e0        MOV        EAX,dword ptr [EBP + status]
00010b78 c1 f8 08        SAR        EAX,0x8
00010b7b 0f b6 c0        MOVZX      EAX,AL
00010b7e 83 f8 01        CMP        EAX,0x1
00010b81 74 18           JZ         LAB_00010b9b
00010b83 83 f8 02        CMP        EAX,0x2
00010b86 74 22           JZ         LAB_00010baa
00010b88 85 c0           TEST       EAX,EAX
00010b8a 75 2d           JNZ        LAB_00010bb9
00010b8c 68 9f 0c        PUSH       DAT_00010c9f                                     = 4Fh    O
01 00
00010b91 e8 92 14        CALL       <EXTERNAL>::puts                                 int puts(char * __s)
00 00
00010b96 83 c4 04        ADD        ESP,0x4
00010b99 eb 2b           JMP        LAB_00010bc6
LAB_00010b9b                                    XREF[1]:     00010b81(j)  
00010b9b 68 a4 0c        PUSH       s_Your_file_is_not_completely_comp_00010ca4      = "Your file is not completely c
01 00
00010ba0 e8 83 14        CALL       <EXTERNAL>::puts                                 int puts(char * __s)
00 00
00010ba5 83 c4 04        ADD        ESP,0x4
00010ba8 eb 1c           JMP        LAB_00010bc6
LAB_00010baa                                    XREF[1]:     00010b86(j)  
00010baa 68 ca 0c        PUSH       s_Your_file_contains_errors_00010cca             = "Your file contains errors"
01 00
00010baf e8 74 14        CALL       <EXTERNAL>::puts                                 int puts(char * __s)
00 00
00010bb4 83 c4 04        ADD        ESP,0x4
00010bb7 eb 0d           JMP        LAB_00010bc6
LAB_00010bb9                                    XREF[1]:     00010b8a(j)  
00010bb9 68 e4 0c        PUSH       s_I_can't_tell_if_your_file_is_XHT_00010ce4      = "I can't tell if your file is 
01 00
00010bbe e8 65 14        CALL       <EXTERNAL>::puts                                 int puts(char * __s)
00 00
00010bc3 83 c4 04        ADD        ESP,0x4
LAB_00010bc6                                    XREF[3]:     00010b99(j), 00010ba8(j), 
            00010bb7(j)  
00010bc6 b8 00 00        MOV        EAX,0x0
00 00
LAB_00010bcb                                    XREF[6]:     000109d8(j), 00010a0b(j), 
            00010a3a(j), 00010a61(j), 
            00010a86(j), 00010b0a(j)  
00010bcb 8b 5d fc        MOV        EBX,dword ptr [EBP + local_8]
00010bce c9              LEAVE
00010bcf c3              RET

根据Ghidra的说法,这将反编译为:

int main(int argc,char **argv)
{
__uid_t __euid;
__uid_t __ruid;
__gid_t __egid;
__gid_t __rgid;
int iVar1;
int __fd;
int iVar2;
__pid_t __pid;
ssize_t sVar3;
uint uVar4;
int status;
char c;
int pipefd [2];
pid_t pid;
int fd;
int in;

__euid = geteuid();
__ruid = geteuid();
setreuid(__ruid,__euid);
__egid = getegid();
__rgid = getegid();
setregid(__rgid,__egid);
if (argv[1] == (char *)0x0) {
fwrite("Please specify the file to verifyn",1,0x22,stderr);
iVar1 = 1;
}
else {
iVar1 = open(argv[1],0);
if (iVar1 < 0) {
perror("open");
iVar1 = 2;
}
else {
__fd = open("/dev/null",2);
if (__fd < 0) {
perror("open");
iVar1 = 5;
}
else {
iVar2 = pipe(pipefd);
if (iVar2 < 0) {
perror("pipe");
iVar1 = 3;
}
else {
__pid = fork();
if (__pid < 0) {
perror("fork");
iVar1 = 4;
}
else if (__pid == 0) {
dup2(pipefd[0],0);
dup2(__fd,1);
dup2(__fd,2);
close(pipefd[1]);
close(__fd);
close(iVar1);
execlp("tidy","tidy","-asxml",0);
perror("execlp");
iVar1 = 5;
}
else {
while( true ) {
sVar3 = read(iVar1,&c,1);
if (sVar3 == 0) break;
write(pipefd[1],&c,1);
}
close(pipefd[1]);
close(pipefd[0]);
close(__fd);
close(iVar1);
waitpid(__pid,&status,0);
uVar4 = status >> 8 & 0xff;
if (uVar4 == 1) {
puts("Your file is not completely compliant");
}
else if (uVar4 == 2) {
puts("Your file contains errors");
}
else if (uVar4 == 0) {
puts("OK!");
}
else {
puts("I can't tell if your file is XHTML-compliant");
}
iVar1 = 0;
}
}
}
}
}
return iVar1;
}

似乎是(总结(在只读模式下使用open打开作为第一个参数传递的文件。如果成功,它将分叉并使用子进程执行整洁,以验证文件是有效的XHTML。

对我来说,这并不是一个明显的弱点,我可以在这里利用它。我已经研究过整洁命令的漏洞,但没有找到任何有用的东西。

任何帮助都将不胜感激!

在常规C代码中,execlp("tidy","tidy","-asxml",0);是不正确的,因为execlp()需要一个空指针参数来标记参数列表的末尾。

当在指针上下文中使用时,0是一个空指针,但事实并非如此。然而,在指针大小和传递约定与int相同的体系结构上,例如32位linux,传递0或传递NULL会生成相同的代码,因此草率不会受到惩罚。

在64位模式下,这样做是不正确的,但您可能会幸运地使用x86_64 ABI,在这种情况下会传递64位0值。

在您自己的代码中,避免此类陷阱,并使用NULL(char *)0作为execlp()的最后一个参数。但在这个列表中,Ghidra生成的代码生成相同的汇编代码,在32位模式中,传递0(char *)0生成相同的代码,所以这里没有问题。

在您的上下文中,execlp("tidy","tidy","-asxml",0);显示了另一个问题:它将在当前的PATH中查找名称为tidy的可执行程序,并以命令行参数-asxmltidy运行此程序。由于它更改了有效的uid和gid,如果程序是setuidroot,这是一个问题,因为您可以在系统目录之前的PATH变量中出现的目录中创建一个名为tidy的程序,并且该程序将使用修改后的权限运行。

另一个潜在的问题是程序没有检查系统调用setreuid()setregid()的故障。尽管这些调用对于传递的参数不太可能失败,如手册页面中所述,但省略对setreuid()的失败返回的检查是一个严重的安全错误在失败的情况下,真实有效的uid(或gid(不会更改,进程可能会以root权限分叉和执行。

最新更新