diff options
Diffstat (limited to 'recipes-security/redhat-security/files/rpm-chksec.sh')
-rw-r--r-- | recipes-security/redhat-security/files/rpm-chksec.sh | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/recipes-security/redhat-security/files/rpm-chksec.sh b/recipes-security/redhat-security/files/rpm-chksec.sh new file mode 100644 index 0000000..983c218 --- /dev/null +++ b/recipes-security/redhat-security/files/rpm-chksec.sh | |||
@@ -0,0 +1,279 @@ | |||
1 | #!/bin/sh | ||
2 | # rpm-chksec | ||
3 | # | ||
4 | # Copyright (c) 2011-2013 Steve Grubb. ALL RIGHTS RESERVED. | ||
5 | # sgrubb@redhat.com | ||
6 | # | ||
7 | # This software may be freely redistributed under the terms of the GNU | ||
8 | # public license. | ||
9 | # | ||
10 | # You should have received a copy of the GNU General Public License | ||
11 | # along with this program; if not, write to the Free Software | ||
12 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
13 | # | ||
14 | # Given an rpm, it will look at each file to check that its compiled with | ||
15 | # the intended flags to make it more secure. Things that are green are OK. | ||
16 | # Anything in yellow could be better but is passable. Anything in red needs | ||
17 | # attention. | ||
18 | # | ||
19 | # If the --all option is given, it will generate a list of rpms and then | ||
20 | # summarize the rpm's state. For yes, then all files are in the expected | ||
21 | # state. Just one file not compiled with the right flags can turn the | ||
22 | # answer to no. Re-run passing that package (instead of --all) for the details. | ||
23 | # | ||
24 | # To save to file: ./rpm-chksec | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | tee output.txt | ||
25 | |||
26 | VERSION="0.5.2" | ||
27 | |||
28 | usage () { | ||
29 | echo "rpm-chksec [--version|--all|<rpmname>...]" | ||
30 | if [ ! -x /usr/bin/filecap ] ; then | ||
31 | echo "You need to install libcap-ng-utils to test capabilities" | ||
32 | fi | ||
33 | if [ $EUID != 0 ] ; then | ||
34 | echo "You might need to be root to read some files" | ||
35 | fi | ||
36 | exit 0 | ||
37 | } | ||
38 | |||
39 | if [ "$1" = "--help" -o $# -eq 0 ] ; then | ||
40 | usage | ||
41 | fi | ||
42 | if [ "$1" = "--version" ] ; then | ||
43 | echo "rpm-chksec $VERSION" | ||
44 | exit 0 | ||
45 | fi | ||
46 | if [ "$1" = "--all" ] ; then | ||
47 | MODE="all" | ||
48 | else | ||
49 | MODE="single" | ||
50 | fi | ||
51 | |||
52 | do_one () { | ||
53 | if ! rpm -q $1 >/dev/null 2>&1 ; then | ||
54 | if [ "$MODE" = "single" ] ; then | ||
55 | echo "$1 is not installed" | ||
56 | exit 1 | ||
57 | else | ||
58 | echo "not installed" | ||
59 | return | ||
60 | fi | ||
61 | fi | ||
62 | files=`rpm -ql $1` | ||
63 | |||
64 | # Look for daemons, need this for later... | ||
65 | DAEMON="" | ||
66 | for f in $files | ||
67 | do | ||
68 | if [ ! -f "$f" ] ; then | ||
69 | continue | ||
70 | fi | ||
71 | if [ `echo "$f" | grep '\/etc\/rc.d\/init.d'` ] ; then | ||
72 | n=`basename "$f"` | ||
73 | t=`which "$n" 2>/dev/null` | ||
74 | if [ x"$t" != "x" ] ; then | ||
75 | DAEMON="$DAEMON $t" | ||
76 | continue | ||
77 | fi | ||
78 | t=`which "$n"d 2>/dev/null` | ||
79 | if [ x"$t" != "x" ] ; then | ||
80 | DAEMON="$DAEMON $t" | ||
81 | continue | ||
82 | fi | ||
83 | t=`cat "$f" 2>/dev/null | grep 'bin' | grep 'exit 5' | grep -v '\$'` | ||
84 | if [ x"$t" != "x" ] ; then | ||
85 | DAEMON="$DAEMON $t" | ||
86 | continue | ||
87 | fi | ||
88 | if [ "$MODE" = "single" ] ; then | ||
89 | echo "Can't find the executable in $f but daemon rules would apply" | ||
90 | fi | ||
91 | elif [ `echo "$f" | grep '\/lib\/systemd\/'` ] ; then | ||
92 | t=`cat "$f" | grep -i '^ExecStart=' | tr '=' ' ' | awk '{ print $2 }'` | ||
93 | if [ x"$t" != "x" ] ; then | ||
94 | DAEMON="$DAEMON $t" | ||
95 | continue | ||
96 | fi | ||
97 | fi | ||
98 | done | ||
99 | |||
100 | # Prevent garbled output when doing --all. | ||
101 | skip_current=0 | ||
102 | |||
103 | for f in $files | ||
104 | do | ||
105 | if [ ! -f "$f" ] ; then | ||
106 | continue | ||
107 | fi | ||
108 | # Some packages have files with ~ in them. This avoids it. | ||
109 | if ! echo "$f" | grep '^/' >/dev/null ; then | ||
110 | continue | ||
111 | fi | ||
112 | if [ ! -r "$f" ] && [ $EUID != 0 ] ; then | ||
113 | if [ $MODE = "single" ] ; then | ||
114 | echo "Please re-test $f as the root user" | ||
115 | else | ||
116 | # Don't print results. | ||
117 | skip_current=1 | ||
118 | echo "Please re-test $1 as the root user" | ||
119 | fi | ||
120 | continue | ||
121 | fi | ||
122 | if ! file "$f" | grep -qw 'ELF'; then | ||
123 | continue | ||
124 | fi | ||
125 | RELRO="no" | ||
126 | if readelf -l "$f" 2>/dev/null | grep -q 'GNU_RELRO'; then | ||
127 | RELRO="partial" | ||
128 | fi | ||
129 | if readelf -d "$f" 2>/dev/null | grep -q 'BIND_NOW'; then | ||
130 | RELRO="full" | ||
131 | fi | ||
132 | PIE="no" | ||
133 | if readelf -h "$f" 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then | ||
134 | PIE="DSO" | ||
135 | if readelf -d "$f" 2>/dev/null | grep -q '(DEBUG)'; then | ||
136 | PIE="yes" | ||
137 | fi | ||
138 | fi | ||
139 | APP="" | ||
140 | if [ x"$DAEMON" != "x" ] ; then | ||
141 | for d in $DAEMON | ||
142 | do | ||
143 | if [ "$f" = "$d" ] ; then | ||
144 | APP="daemon" | ||
145 | break | ||
146 | fi | ||
147 | done | ||
148 | fi | ||
149 | if [ x"$APP" = "x" ] ; then | ||
150 | # See if this is a library or a setuid app | ||
151 | if [ `echo "$f" | grep '\/lib' | grep '\.so'` ] ; then | ||
152 | APP="library" | ||
153 | elif [ `find "$f" -perm -004000 -type f -print` ] ; then | ||
154 | APP="setuid" | ||
155 | elif [ `find "$f" -perm -002000 -type f -print` ] ; then | ||
156 | APP="setgid" | ||
157 | elif [ -x /usr/bin/filecap ] && [ `filecap "$f" 2> /dev/null | wc -w` -gt 0 ] ; then | ||
158 | APP="setcap" | ||
159 | else | ||
160 | syms1=`/usr/bin/readelf -s "$f" 2>/dev/null | egrep ' connect@.*GLIBC| listen@.*GLIBC| accept@.*GLIBC|accept4@.*GLIBC'` | ||
161 | syms2=`/usr/bin/readelf -s "$f" 2>/dev/null | egrep ' getaddrinfo@.*GLIBC| getnameinfo@.*GLIBC| getservent@.*GLIBC| getservbyname@.*GLIBC| getservbyport@.*GLIBC|gethostbyname@.*GLIBC| gethostbyname2@.*GLIBC| gethostbyaddr@.*GLIBC| gethostbyaddr2@.*GLIBC'` | ||
162 | if [ x"$syms1" != "x" ] ; then | ||
163 | if [ x"$syms2" != "x" ] ; then | ||
164 | APP="network-ip" | ||
165 | else | ||
166 | APP="network-local" | ||
167 | fi | ||
168 | fi | ||
169 | fi | ||
170 | fi | ||
171 | if [ x"$APP" = "x" ] ; then | ||
172 | APP="exec" | ||
173 | fi | ||
174 | |||
175 | # OK, ready for the output | ||
176 | if [ "$MODE" = "single" ] ; then | ||
177 | printf "%-56s %-10s " "$f" $APP | ||
178 | if [ "$APP" = "daemon" -o "$APP" = "setuid" -o "$APP" = "setgid" -o "$APP" = "setcap" -o "$APP" = "network-ip" -o "$APP" = "network-local" ] ; then | ||
179 | if [ "$RELRO" = "full" ] ; then | ||
180 | printf "\033[32m%-7s\033[m " $RELRO | ||
181 | elif [ "$RELRO" = "partial" ] ; then | ||
182 | printf "\033[33m%-7s\033[m " $RELRO | ||
183 | else | ||
184 | printf "\033[31m%-7s\033[m " $RELRO | ||
185 | fi | ||
186 | if [ "$PIE" = "yes" ] ; then | ||
187 | printf "\033[32m%-4s\033[m" $PIE | ||
188 | else | ||
189 | printf "\033[31m%-4s\033[m" $PIE | ||
190 | fi | ||
191 | elif [ "$APP" = "library" ] ; then | ||
192 | if [ "$RELRO" = "full" -o "$RELRO" = "partial" ] ; then | ||
193 | printf "\033[32m%-7s\033[m " $RELRO | ||
194 | else | ||
195 | printf "\033[31m%-7s\033[m " $RELRO | ||
196 | fi | ||
197 | printf "\033[32m%-4s\033[m" $PIE | ||
198 | else | ||
199 | # $APP = exec - we want partial relro | ||
200 | if [ "$RELRO" = "no" ] ; then | ||
201 | printf "\033[31m%-7s\033[m " $RELRO | ||
202 | else | ||
203 | printf "\033[32m%-7s\033[m " $RELRO | ||
204 | fi | ||
205 | printf "\033[32m%-4s\033[m" $PIE | ||
206 | fi | ||
207 | echo | ||
208 | else | ||
209 | if [ "$APP" = "daemon" -o "$APP" = "setuid" -o "$APP" = "setgid" -o "$APP" = "setcap" -o "$APP" = "network-ip" -o "$APP" = "network-local" ] ; then | ||
210 | if [ "$RELRO" = "no" ] ; then | ||
211 | RELRO_SUM="no" | ||
212 | APP_SUM="$APP" | ||
213 | fi | ||
214 | if [ "$PIE" = "no" ] ; then | ||
215 | PIE_SUM="no" | ||
216 | APP_SUM="$APP" | ||
217 | fi | ||
218 | elif [ "$APP" = "library" ] ; then | ||
219 | if [ "$RELRO" = "no" ] ; then | ||
220 | RELRO_SUM="no" | ||
221 | APP_SUM="$APP" | ||
222 | fi | ||
223 | # $APP = exec - must have partial or full relro | ||
224 | elif [ "$RELRO" = "no" ] ; then | ||
225 | RELRO_SUM="no" | ||
226 | APP_SUM="$APP" | ||
227 | fi | ||
228 | fi | ||
229 | done | ||
230 | } | ||
231 | |||
232 | if [ "$MODE" = "single" ] ; then | ||
233 | printf "%-56s %-10s %-7s %-4s" "FILE" "TYPE" "RELRO" "PIE" | ||
234 | echo | ||
235 | for i; do | ||
236 | f=$(basename $1) | ||
237 | # Strip the .rpm extension, if present. | ||
238 | do_one ${f%%.rpm} | ||
239 | shift | ||
240 | done | ||
241 | exit 0 | ||
242 | fi | ||
243 | |||
244 | # Skip the kernel as its special | ||
245 | packages=`rpm -qa --queryformat "%{NAME}.%{ARCH}\n" | egrep -v 'kernel.|debuginfo.|.noarch|gpg-pubkey' | sort` | ||
246 | printf "%-50s %-5s %-4s %-14s" "PACKAGE" "RELRO" "PIE" "CLASS" | ||
247 | echo | ||
248 | for p in $packages | ||
249 | do | ||
250 | RELRO_SUM="yes" | ||
251 | PIE_SUM="yes" | ||
252 | APP_SUM="" | ||
253 | printf "%-50s " $p | ||
254 | do_one $p | ||
255 | if [[ $skip_current -eq 1 ]] ; then | ||
256 | continue | ||
257 | fi | ||
258 | if [ "$RELRO_SUM" = "yes" ] ; then | ||
259 | printf "\033[32m%-5s\033[m " "$RELRO_SUM" | ||
260 | else | ||
261 | printf "\033[31m%-5s\033[m " "$RELRO_SUM" | ||
262 | fi | ||
263 | if [ "$PIE_SUM" = "yes" ] ; then | ||
264 | printf "\033[32m%-4s\033[m" "$PIE_SUM" | ||
265 | if [ "$RELRO_SUM" = "no" ] ; then | ||
266 | printf " %-14s" "$APP_SUM" | ||
267 | fi | ||
268 | else | ||
269 | if [ "$APP_SUM" = "network-local" ] ; then | ||
270 | printf "\033[33m%-4s\033[m %-14s" "$PIE_SUM" "$APP_SUM" | ||
271 | else | ||
272 | printf "\033[31m%-4s\033[m %-14s" "$PIE_SUM" "$APP_SUM" | ||
273 | fi | ||
274 | fi | ||
275 | echo | ||
276 | done | ||
277 | exit 0 | ||
278 | |||
279 | |||