https://nsc.aoeu.com/csb435/week-03
Let's CLI like it's goin' out of style
------- Mo Tu We Th Fr Sa Su 01 APR 6 7 8 9 10 11 12 02 APR 13 14 15 16 17 18 19 assignment 1 03 APR 20 21 22 23 24 25 26 cp 1 04 A/M 27 28 29 30 1 2 3 assignment 2 05 MAY 4 5 6 7 8 9 10 cp 2 06 MAY 11 12 13 14 15 16 17 CLASS REMOTE / assignment 3 07 MAY 18 19 20 21 22 23 24 cp 3 08 MAY 25 26 27 28 29 30 31 assignment 4 09 JUN 1 2 3 4 5 6 7 cp 4 10 JUN 8 9 10 11 12 13 14 ripen final 11 JUN 15 16 17 18 19 20 21 no class! Go graduate!
In the mid-1990s, I wrote a web forum
I thought I was pretty clever.
Users started posting messages with math in them.

What do you think happened?
The < character was interpreted as HTML tag start.

This is what the html looked like:
<p>
Poster: wbagg<br>
Date: 199x-04-23 04:43:05<br>
<p>
I'm trying to figure out where "y < 0" in "x^2 + 5x + 3 = 0"
<center>
<hr width="600" size="1">
<font size="1" face="Arial, Helvetica">
This is bad, but is it a security problem?

<pre> <!--#include virtual="/etc/passwd"> </pre>
for (i = 0; i < length; i++) {
ch = str[i];
if (ch == '<') {
printf("<");
} else {
printf(ch)
}
}
Problem solved! Right?

Over weeks, I kept finding new characters to escape.
Lab #1 !
Injection Attack: when user input changes the meaning of commands or content
These are always in the CWE Top 25 and OWASP Top 10 most common security flaws.
Four conditions create injection vulnerability:
User input enters your program from many sides
stdin)
INSERT INTO Students (firstname) VALUES ('Elaine');
vs
INSERT INTO Students (firstname) VALUES ('Robert'); DROP
TABLE students; --');
SELECT * FROM users WHERE username = 'alice';
INSERT INTO products (name, price) VALUES ('Widget', 9.99);
UPDATE accounts SET balance = 1000 WHERE id = 42;
DELETE FROM logs WHERE date < '2025-01-01';
Straightforward when queries are static.
Real applications need to build queries from user input:
username = get_user_input()
query = "SELECT * FROM users WHERE username = '"
+ username + "'"
execute(query)
SELECT * FROM users WHERE username = 'Robert'; DROP TABLE users; --'
Three techniques used:
--)Try csb435/week-03/login_vulnerable.py
$ ssh class.nsc.aoeu.com
$ cd csb435/week-03/
$ ./login_vulnerable.py
Username: admin
Password: not-treefrogs
Executing query: SELECT *
FROM users
WHERE username='admin'
AND password='not-treefrogs'
LOGIN FAILED
Invalid credentialsQuery Code:
query = "SELECT * FROM users WHERE username='" + user
+ "' AND password='" + pass + "'"
admin' --SELECT * FROM users WHERE username='admin' --' AND password='foo'`
Query Code:
query = "SELECT * FROM users WHERE username='" + user
+ "' AND password='" + pass + "'"
' OR '1' = '1
SELECT * FROM users WHERE username='foo'
AND password='' OR '1' = '1'
SELECT * FROM users WHERE username=''
UNION SELECT
NULL,
group_concat(username || ':' || password || ':' || role, ' - '),
'x',
'admin'
FROM users --' AND password='foo'
LOGIN SUCCESSFUL
Welcome, admin:treefrogs:admin - alice:CryptoIsFun:user - bob:ipreferjava:user ...
Bad Idea #1: Input Validation
Only allow alphanumeric characters?
Bad Idea #2: Escaping Quotes
Replace ' with '' or \'?
stmt = db.prepare(
"SELECT * FROM users WHERE username = ? AND password = ?"
)
stmt.setString(1, username)
stmt.setString(2, password)
result = stmt.executeQuery()
? are placeholders for dataSeparation of Code and Data
'; DROP TABLE users; -- is treated as a literal username.
Executing shell commands from your program
Many languages provide this:
Runtime.getRuntime().exec(), ProcessBuilder() in Javapopen() in C, Pythonsystem() in C, Python, Rubyexec() in PHP, Pythonshell_exec() in PHPsubprocess.run() in Python
#!/usr/bin/env python3
import os, sys
image_name = sys.argv[1]
base = image_name.rsplit(".", 1)[0]
output = base + ".gif"
cmd = f"magick {image_name} {output}"
os.system(cmd)
Input: foo.png ; rm -rf /
Resulting command: magick foo.png ; rm -rf / foo.gif
Many characters have special meaning in shells:
| Character | Meaning |
|---|---|
; |
Command separator |
& |
Background execution |
\| |
Pipe output to next command |
` |
Command substitution |
$() |
Command substitution |
> < |
Redirection |
\n |
Newline (command separator) |
Best practice: Don't use shell commands
Files.delete() os.unlink() vs running rm {filename}Use explicit arguments as lists, not strings when running shell commands
| Vulnerable | Good |
|---|---|
os.system(f"rm {filename}")
|
subprocess.run(["rm", filename])
|
Runtime.getRuntime()
.exec("rm " + filename);
|
Files.delete(Path.of(filename)); |
If you must build command strings:
; | & $ ( ) < > \n \ ``But really, use builtins / libraries where possible.
What's wrong with this python code?
content = input("Say something witty: ")
print(f'You said {content}')
What's wrong with this python code?
content = input("Say something witty: ")
print(f'You said {content}')
In python2, input() was "read + eval" under the hood.
Say something witty: 5 + 7 * 2 You said 19
Python2 had raw_input() added later, which became input in Python3.
Dynamic code execution in interpreted languages:
eval() in Python, JavaScript, Ruby, Perl, PHPexec() in Pythoncompile() in Python/e flag in Perl
expression = input("Enter calculation: ")
result = eval(expression)
print("Result:", result)
...
Enter calculation: __import__('os').system('rm -rf /')
__import__ loads modules dynamicallyos.system() executes shell commandsBest practice: Never use eval() or dynamic code execution
If you absolutely must:
But really, redesign to avoid it.