Overview of basic aspects of Web System Security
Disect root causes of recent high profile vulnerabilities
Custom code running on a web server
or else:
bobby-tables.com
Statistics for 2013
Market share counts installations, not active users
Attacks enabled by sites:
n0p.net 2006
April 7th 2014:
A missing bounds check in the handling of the TLS heartbeat extension can be used to reveal up to 64kB of memory to a connected client or server
TLS clients using affected OpenSSL instances are also vulnerable
"reverse heartbleed"
Affects products including IP phone systems and telepresence (video conferencing) systems
Buffer under-read:
unsigned int payload;
unsigned int padding = 16; /* Use minimum padding */
/* Read type and payload length first */
hbtype = *p++;
n2s(p, payload); //n2s macro copies 16 bits from p to payload (length) without validation!
pl = p;
if (s->msg_callback)
s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
&s->s3->rrec.data[0], s->s3->rrec.length,
s, s->msg_callback_arg);
if (hbtype == TLS1_HB_REQUEST)
{
unsigned char *buffer, *bp;
int r;
/* Allocate memory for the response, size is 1 byte
* message type, plus 2 bytes payload length, plus
* payload, plus padding
*/
buffer = OPENSSL_malloc(1 + 2 + payload + padding); //magic numbers, \o/
bp = buffer;
/* Enter response type, length and copy payload */
//...
/* Random padding */
RAND_pseudo_bytes(bp, padding);
r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
unsigned int payload;
unsigned int padding = 16; /* Use minimum padding */
if (s->msg_callback)
s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
&s->s3->rrec.data[0], s->s3->rrec.length,
s, s->msg_callback_arg);
+ /* Read type and payload length first */
+ if (1 + 2 + 16 > s->s3->rrec.length)
+ return 0; /* silently discard */
+ hbtype = *p++;
+ n2s(p, payload); //copy 16 bits from p as payload length
+ if (1 + 2 + payload + 16 > s->s3->rrec.length)
+ return 0; /* silently discard per RFC 6520 sec. 4 */
+ pl = p;
+
if (hbtype == TLS1_HB_REQUEST)
{
unsigned char *buffer, *bp;
+ unsigned int write_length = 1 /* heartbeat type */ +
+ 2 /* heartbeat length */ +
+ payload + padding;
int r;
+ if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
+ return 0;
+
/* Allocate memory for the response, size is 1 byte
* message type, plus 2 bytes payload length, plus
* payload, plus padding
*/
+ buffer = OPENSSL_malloc(write_length);
bp = buffer;
/* Enter response type, length and copy payload */
//...
/* Random padding */
RAND_pseudo_bytes(bp, padding);
+ r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length);
if (r >= 0 && s->msg_callback)
s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+ buffer, write_length,
s, s->msg_callback_arg);
Implicit trust of open source
Nobody looked (or admitted to looking)
The code was too horrible
Hoped "upstream" could deal with it.
"Horrible code actively discourages outside involvement - the barrier to entry for other developers is too high. Everyone looks at it, and goes back to doing their own stuff, hoping like heck that the upstream maintainers know what they are doing and care"
Research prompted by heartbleed uncovered a custom malloc() replacement that:
Effective as an expoit mitigation countermeasure
Bourne Again SHell
aka "bashdoor"
1989-2014 (25 years)
In the beginning there was the command line.
env x = "() { :;}; echo 'u r pwned'| wall"
bash -c "echo am I pwned?"
Innocent enough?
Who calls out to bash anyways?
+ #define SEVAL_FUNCDEF 0x080 /* only allow function definitions */
+ #define SEVAL_ONECMD 0x100 /* only allow a single command */
Opaque state machines!
strcpy (temp_string + char_index + 1, string);
- if (posixly_correct == 0 || legal_identifier (name))
- parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
-
- /* Ancient backwards compatibility. Old versions of bash exported
- functions like name()=() {...} */
- if (name[char_index - 1] == ')' && name[char_index - 2] == '(')
- name[char_index - 2] = '\0';
+ /* Don't import function names that are invalid identifiers from the
+ environment, though we still allow them to be defined as shell
+ variables. */
+ if (legal_identifier (name))
+ parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
if (temp_var = find_function (name))
'Old' versions of bash...
report_error (_("error importing function definition for `%s'"), name);
}
-
- /* ( */
- if (name[char_index - 1] == ')' && name[char_index - 2] == '\0')
- name[char_index - 2] = '('; /* ) */
}
#if defined (ARRAY_VARS)
dispose_fd_bitmap (bitmap);
discard_unwind_frame ("pe_dispose");
+
+ if (flags & SEVAL_ONECMD)
+ break;
}
}
Only evaluate one.
struct fd_bitmap *bitmap;
+ if ((flags & SEVAL_FUNCDEF) && command->type != cm_function_def)
+ {
+ internal_warning ("%s: ignoring function definition attempt", from_file);
+ should_jump_to_top_level = 0;
+ last_result = last_command_exit_value = EX_BADUSAGE;
+ break;
+ }
+
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
begin_unwind_frame ("pe_dispose");
Only allow function definitions (don't call them!)
goto return0;
}
- else if (var = find_variable_last_nameref (temp1))
+ else if (var && (invisible_p (var) || var_isset (var) == 0))
+ temp = (char *)NULL;
+ else if ((var = find_variable_last_nameref (temp1)) && var_isset (var) &&
+ invisible_p (var) == 0)
{
temp = nameref_cell (var);
I don't even.... invisible_p? (global!)
Web security has many layers
All the moving pieces must be secured individually and as a whole system
Many eyes do help, they must be active
http://www.fortiguard.com/fortiguard_labs/threat_monitor
Wouldn't You Prefer A Nice Game Of Chess?