blob: 3425e53d0c3127464e7ad5d9aaa3cd041423b350 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#!/bin/sh
# Executable patcher
# Copyright (C) 2024-2025 Nguyễn Gia Phong
#
# This file is part of taosc.
#
# Taosc is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Taosc is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with taosc. If not, see <https://www.gnu.org/licenses/>.
set -eux -o pipefail
save_exit_code() {
set +e
timeout -k 1 $1 ${@:2} 1>/dev/null 2>&1
exit_code=$?
set -e
}
bad() {
save_exit_code $@
test $exit_code -gt 128 ||
test $exit_code -ge 124 -a $exit_code -le 127 # timeout
}
if test $# -lt 4
then
echo Usage: taosc-fix WORKDIR TIMEOUT EXECUTABLE PROOFS-OF-CONCEPT [OPTION]...
exit 1
fi
wd="$(realpath $1)"
test -d "$wd"
timeout=$2
bin="$wd/$(basename $3)"
binary="$(realpath $3)"
test -x "$binary"
poc="$(realpath $4)"
test -d "$poc"
test "$(ls -A "$poc")"
options="${@:5}" # TODO: interpolation
mkdir -p "$wd"
rm -fr "$wd/poc"
cp -r "$poc" "$wd/poc"
for exploit in "$wd"/poc/*
do
gdb --batch --ex run --ex backtrace --args\
"$binary" $options "$exploit" 2>/dev/null |
grep '^#[0-9]\+ \+0x[0-9a-f]\+' |
awk '!$7 || $7 == bin {print $1, $2}' "bin=$binary" |
sed 's/^#//'
done | sort -n | uniq > "$wd/stack-trace"
grep '^0 0x[0-9a-f]\+$' "$wd/stack-trace" |
sed 's/^0 0x0*//' > "$wd/call-trace"
# Stack trace contains return addresses, not call addresses:
# https://devblogs.microsoft.com/oldnewthing?p=96116
grep -v '^0 0x[0-9a-f]\+$' "$wd/stack-trace" |
sed 's/^[0-9]\+ 0x0*//' |
taosc-trace-call "$binary" >> "$wd/call-trace"
rm -f "$wd/patch-location"
pushd DATA_DIR 1>/dev/null
trap 'popd 1>/dev/null' EXIT
taosc-scout "$binary" < "$wd/call-trace" |
while read loc destinations && test ! -f "$wd/patch-location"
do
e9tool -100 -M addr=0x$loc -P 'if dest()@jump goto' -o "$bin.jump" "$binary"
rm -f "$wd/destinations"
for dest in $destinations
do
# In case $wd/poc got poluted
rm -fr "$wd/poc"
cp -r "$poc" "$wd/poc"
for exploit in "$wd/poc"/*
do
if bad $timeout env TAOSC_DEST=0x$dest "$bin.jump" $options "$exploit"
then
continue 2 # next destination
fi
done
echo $loc > "$wd/patch-location"
echo $dest >> "$wd/destinations"
done
done 1>/dev/null 2>&1
test -s "$wd/patch-location"
test -s "$wd/destinations"
stack_size=$(taosc-measure-stack "$binary" < "$wd/patch-location")
patch_loc=0x$(< "$wd/patch-location")
e9tool -100 -M addr=$patch_loc -P 'report()@cover' -o "$bin.covered" "$binary"
e9tool -100 -M addr=$patch_loc -P 'log(state)@collect'\
-o "$bin.collect" "$binary"
e9tool -100 -M addr=$patch_loc -P 'if dest(state)@patch goto'\
-o "$bin.patched" "$binary"
# TODO: FUZZOLIC's options
fuzzolic -kmprst 90000 -i "$poc" -o "$wd/fuzzolic" -- "$binary" $option @@
rm -fr "$wd/input"
mkdir -p "$wd/input/benign"
cp -r "$poc" "$wd/input/malicious"
# TODO: use parallel
for dat in "$wd"/fuzzolic/fuzzolic-*/test_case_*.dat
do
if taosc-reach $timeout "$bin.covered" $options "$dat" 1>/dev/null 2>&1
then
if bad $timeout "$binary" $options "$dat"
then
cp $dat "$wd/input/malicious"
else
cp $dat "$wd/input/benign"
fi
fi
done
rm -fr "$wd/values"
for input_dir in "$wd"/input/*
do
output_dir="$wd/values/$(basename "$input_dir")"
mkdir -p "$output_dir"
# TODO: use parallel
for input in "$input_dir"/*
do
output="$output_dir/$(basename "$input")"
save_exit_code $timeout\
env TAOSC_STACK_SIZE=$stack_size TAOSC_OUTPUT=$output\
"$bin.collect" $options "$input"
done
done
# vim: filetype=sh.m4
|