Secure Software Development

CSB 435 - Secure Software Development

Week 03 - Injection Attacks

https://nsc.aoeu.com/csb435/week-03

Bash Bash - SSH edition!

Let's CLI like it's goin' out of style

Class at a glance

------- 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!

The Early Web

In the mid-1990s, I wrote a web forum

I thought I was pretty clever.

Math Problems

Users started posting messages with math in them.

Good forum image

What do you think happened?

Less than zero

The < character was interpreted as HTML tag start.

Good forum image

Under the hood

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">

YCPGW?

This is bad, but is it a security problem?

Thing that could go wrong

Server Side Includes

Worse forum image

<pre>
<!--#include virtual="/etc/passwd">
</pre>

Simplistic fix?

for (i = 0; i < length; i++) {
    ch = str[i];
    if (ch == '<') {
        printf("&lt;");
    } else {
        printf(ch)
    }
}

Problem solved! Right?

Escape from HTMLcratraz

Whack a mole with html entities

Over weeks, I kept finding new characters to escape.

Happy Conservatives

Lab #1 !

Injection Attacks

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.

Not the Botox kind

Four conditions create injection vulnerability:

  1. Program uses a command interpreter
  2. Commands constructed dynamically at runtime
  3. User input used to construct commands
  4. Program fails to prevent input from changing command meaning

Attack Surface

User input enters your program from many sides

Bobby Tables

https://xkcd.com/327/

Bobby Tables XKCD comic

Robert'); DROP TABLE students; --

Bobby Tables (cont)

Bobby Tables XKCD comic

INSERT INTO Students (firstname) VALUES ('Elaine');

vs

INSERT INTO Students (firstname) VALUES ('Robert'); DROP
    TABLE students; --');

SQL Basics

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.

Dynamic SQL Construction

Real applications need to build queries from user input:

username = get_user_input()
query = "SELECT * FROM users WHERE username = '"
        + username + "'"
execute(query)

Anatomy of the Attack

SELECT *
  FROM users
  WHERE username = 'Robert'; DROP TABLE users; --'


Three techniques used:

  1. Metacharacter injection (quote to close original string)
  2. Statement separator (semicolon)
  3. Comment to neutralize remaining text (--)

Would you like to play a game?

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 credentials

Attack #1

Query Code:

query = "SELECT * FROM users WHERE username='" + user
        + "' AND password='" + pass + "'"



SELECT * FROM users WHERE username='admin' --' AND password='foo'`

Attack #2

Query Code:

query = "SELECT * FROM users WHERE username='" + user
        + "' AND password='" + pass + "'"



SELECT * FROM users WHERE username='foo'
         AND password='' OR '1' = '1'

Attack #3

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 ...

How NOT To Fix SQL Injection

Bad Idea #1: Input Validation

Only allow alphanumeric characters?

How NOT To Fix SQL Injection

Bad Idea #2: Escaping Quotes

Replace ' with '' or \'?

SQL Injection protection: Prepared Statements

stmt = db.prepare(
    "SELECT * FROM users WHERE username = ? AND password = ?"
)
stmt.setString(1, username)
stmt.setString(2, password)
result = stmt.executeQuery()

You gotta keep 'em separated

Separation of Code and Data

  1. SQL structure sent to database first
  2. Database compiles/prepares the query
  3. Parameters sent separately
  4. Data inserted without parsing
  5. No metacharacters can change query meaning

'; DROP TABLE users; -- is treated as a literal username.

Command Injection

Executing shell commands from your program

Many languages provide this:

Hard or soft 'g'?

#!/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)

Hard or soft 'g'?

Input: foo.png ; rm -rf /

Resulting command: magick foo.png ; rm -rf / foo.gif

Shell Metacharacters

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)

How To Prevent Command Injection

Best practice: Don't use shell commands

How To Prevent Command Injection

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));

Command Injection Defenses

If you must build command strings:

  1. Validate input against strict allow list
  2. Reject dangerous metacharacters: ; | & $ ( ) < > \n \ ``
  3. Never try to "fix" input - reject it instead
  4. Use shell escaping functions from your language

But really, use builtins / libraries where possible.

Two subtle a vulnerability

What's wrong with this python code?

content = input("Say something witty: ")
print(f'You said {content}')

Two decades of bad design

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.

Code Injection

Dynamic code execution in interpreted languages:

Code Injection Example: Calculator

expression = input("Enter calculation: ")
result = eval(expression)
print("Result:", result)
...

Enter calculation: __import__('os').system('rm -rf /')

Code Injection Defenses

Best practice: Never use eval() or dynamic code execution

If you absolutely must:

  1. Validate input with strict allow lists
  2. Reject any metacharacters: quotes, semicolons, etc.
  3. Consider using restricted execution environments
  4. Use language-specific safe alternatives


But really, redesign to avoid it.