mirror of
https://github.com/openwrt/packages.git
synced 2026-10-12 05:57:04 +04:00
ddns-scripts: fix root command injection through ddns_dateformat
The date format read from the UCI option ddns.global.ddns_dateformat was
embedded into a command string that is later executed through "eval", both
for the recurring log timestamps
DATE_PROG="date +'$ddns_dateformat'"
...
write_log 5 "PID '$$' started at $(eval $DATE_PROG)"
and for the "last update" timestamp in the updater
EPOCH_TIME="date -d @$EPOCH_TIME +'$ddns_dateformat'"
write_log 7 "last update: $(eval $EPOCH_TIME)"
The value is only wrapped in single quotes, so a single quote inside it
closes that quote and starts a new shell word. A user who can write the ddns
configuration - a delegated DDNS operator who was never granted shell access
- can set
ddns_dateformat="%F'; touch /tmp/pwned; '"
and have arbitrary commands run as root, because the updater runs as root.
The injection triggers on the next start of the updater, so in practice on
the next reconfiguration or reboot.
Stop building shell code from the option. Provide date_prog() as an ordinary
shell function and pass the format as a single quoted argument in both
places, which leaves no way for its content to be interpreted by the shell.
The remaining use of ddns_dateformat in dynamic_dns_updater.sh, for
NEXT_CHECK_TIME, already substituted it as a quoted argument without eval
and was not affected.
luci-app-ddns consumes the same option and is fixed separately in the LuCI
repository.
Reported-by: Matthew Hickey (Hacker Fantastic, https://hacker.house)
Fixes: 1c20dcb71a ("ddns-scripts: update to 2.7.6-1")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
1 parent
99c244f744
commit
7364629d70
3 files changed
+17
-14
No files matched your search
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ddns-scripts
|
||||
PKG_VERSION:=2.8.4
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
||||
|
||||
@@ -121,7 +121,11 @@ ddns_loglines=$((ddns_loglines + 1)) # correct sed handling
|
||||
|
||||
# format to show date information in log and luci-app-ddns default ISO 8601 format
|
||||
ddns_dateformat=$(uci -q get ddns.global.ddns_dateformat) || ddns_dateformat="%F %R"
|
||||
DATE_PROG="date +'$ddns_dateformat'"
|
||||
|
||||
# Print the current date using the configured format.
|
||||
# Do not turn this into a command string that is run through "eval": the format
|
||||
# is read from UCI and a single quote inside it would start a new shell word.
|
||||
date_prog() { date +"$ddns_dateformat"; }
|
||||
|
||||
# USE_CURL if GNU Wget and cURL installed normally Wget is used by do_transfer()
|
||||
# to change this use global option use_curl '1'
|
||||
@@ -1121,17 +1125,17 @@ trap_handler() {
|
||||
|
||||
case $1 in
|
||||
0) if [ $__ERR -eq 0 ]; then
|
||||
write_log 5 "PID '$$' exit normal at $(eval $DATE_PROG)${N}"
|
||||
write_log 5 "PID '$$' exit normal at $(date_prog)${N}"
|
||||
else
|
||||
write_log 4 "PID '$$' exit WITH ERROR '$__ERR' at $(eval $DATE_PROG)${N}"
|
||||
write_log 4 "PID '$$' exit WITH ERROR '$__ERR' at $(date_prog)${N}"
|
||||
fi ;;
|
||||
1) write_log 6 "PID '$$' received 'SIGHUP' at $(eval $DATE_PROG)"
|
||||
1) write_log 6 "PID '$$' received 'SIGHUP' at $(date_prog)"
|
||||
# reload config via starting the script again
|
||||
/usr/lib/ddns/dynamic_dns_updater.sh -v "0" -S "$__SECTIONID" -- start || true
|
||||
exit 0 ;; # and leave this one
|
||||
2) write_log 5 "PID '$$' terminated by 'SIGINT' at $(eval $DATE_PROG)${N}";;
|
||||
3) write_log 5 "PID '$$' terminated by 'SIGQUIT' at $(eval $DATE_PROG)${N}";;
|
||||
15) write_log 5 "PID '$$' terminated by 'SIGTERM' at $(eval $DATE_PROG)${N}";;
|
||||
2) write_log 5 "PID '$$' terminated by 'SIGINT' at $(date_prog)${N}";;
|
||||
3) write_log 5 "PID '$$' terminated by 'SIGQUIT' at $(date_prog)${N}";;
|
||||
15) write_log 5 "PID '$$' terminated by 'SIGTERM' at $(date_prog)${N}";;
|
||||
*) write_log 13 "Unhandled signal '$1' in 'trap_handler()'";;
|
||||
esac
|
||||
|
||||
|
||||
@@ -174,14 +174,14 @@ ERR_LAST=$? # save return code - equal 0 if SECTION_ID found
|
||||
[ $VERBOSE -le 1 ] && VERBOSE=2 # force console out and logfile output
|
||||
[ -f $LOGFILE ] && rm -f $LOGFILE # clear logfile before first entry
|
||||
write_log 7 "************ ************** ************** **************"
|
||||
write_log 5 "PID '$$' started at $(eval $DATE_PROG)"
|
||||
write_log 5 "PID '$$' started at $(date_prog)"
|
||||
write_log 7 "ddns version : $VERSION"
|
||||
write_log 7 "uci configuration:${N}$(uci -q show ddns | grep '=service' | sort)"
|
||||
write_log 14 "Service section '$SECTION_ID' not defined"
|
||||
}
|
||||
|
||||
write_log 7 "************ ************** ************** **************"
|
||||
write_log 5 "PID '$$' started at $(eval $DATE_PROG)"
|
||||
write_log 5 "PID '$$' started at $(date_prog)"
|
||||
write_log 7 "ddns version : $VERSION"
|
||||
write_log 7 "uci configuration:${N}$(uci -q show ddns.$SECTION_ID | sort)"
|
||||
# write_log 7 "ddns version : $(opkg list-installed ddns-scripts | cut -d ' ' -f 3)"
|
||||
@@ -285,8 +285,7 @@ if [ $LAST_TIME -eq 0 ]; then
|
||||
write_log 7 "last update: never"
|
||||
else
|
||||
EPOCH_TIME=$(( $(date +%s) - $CURR_TIME + $LAST_TIME ))
|
||||
EPOCH_TIME="date -d @$EPOCH_TIME +'$ddns_dateformat'"
|
||||
write_log 7 "last update: $(eval $EPOCH_TIME)"
|
||||
write_log 7 "last update: $(date -d @$EPOCH_TIME +"$ddns_dateformat")"
|
||||
fi
|
||||
|
||||
# verify Proxy server and set environment
|
||||
@@ -309,7 +308,7 @@ ERR_LAST=$?
|
||||
[ $use_ipv6 -eq 1 ] && expand_ipv6 "$REGISTERED_IP" REGISTERED_IP
|
||||
|
||||
# loop endlessly, checking ip every check_interval and forcing an updating once every force_interval
|
||||
write_log 6 "Starting main loop at $(eval $DATE_PROG)"
|
||||
write_log 6 "Starting main loop at $(date_prog)"
|
||||
while : ; do
|
||||
|
||||
get_current_ip CURRENT_IP # read current IP
|
||||
@@ -396,7 +395,7 @@ while : ; do
|
||||
[ $FORCE_SECONDS -eq 0 ] && write_log 6 "Configured to run once"
|
||||
[ $VERBOSE -gt 1 -o $FORCE_SECONDS -eq 0 ] && exit 0
|
||||
|
||||
write_log 6 "Rerun IP check at $(eval $DATE_PROG)"
|
||||
write_log 6 "Rerun IP check at $(date_prog)"
|
||||
done
|
||||
# we should never come here there must be a programming error
|
||||
write_log 12 "Error in 'dynamic_dns_updater.sh - program coding error"
|
||||
Reference in new issue
Block a user