SlideShare a Scribd company logo
What application security tools vendors don’t want you to know and holes they will never find! Mark Curphey John Viega
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
How Important is Context?
 
 
 
 
Mozilla vs. Klocwork  611 “defects”  72 “vulnerabilities”  3 verified bugs  99.5% useless?
 
 
 
What kind of talk is this? Tools that try to find security holes in software Way for us to understand and rationalize why they are so bad and unlikely to get much better soon It is a realistic state of the union about the current state of application security technology and how it is being marketed and applied Dr. Holger Peine http://fhgonline.fraunhofer.de/server?suche-publica&num=048.06/D&iese (N.B. about overly generous quote to Cenzic) Arian Evans http://www.owasp.org/index.php/Image:AppSec2005DC-Arian_Evans_Tools-Taxonomy.ppt
New Topic How software is built in the real world Security Reference Frame Types of Tools What They Realistically Find
 
 
 
How is security built in the real world?
 
 
 
How is security built in the real world?
How is security built in the real world?
 
Implementation Bugs  vs. Design Flaws
Security Frame of Reference Name Description Configuration Management Configs, security managers, web server settings etc. Authentication Knowing users and entities are who they claim to be Authorization Who can do what to whom, TOCTOU etc. Data Protection (Transit & Storage) Encrypted passwords, on-wire protection, channel sinks, encrypted configuration files etc. Data Validation Valid, well formed, free of malicious payloads etc. Auditing and Logging Knowing who does what to whom etc. Error & Exception Handling What happens when the pooh hits the fan etc. User Management Password reset, registration, licensing etc.
 
Scorecard * unscientific, based on experience stands reasonable chance of finding issues “ could” find some issues unlikely to find issues with confidence Security Reference Frame Effectiveness of Assessment Tools Web App Scanners Static Code Analysis Binary Analysis Bug Flaw Bug  Flaw Bug Flaw Configuration Management * * Authentication * * Authorization * * Data Protection (Transit & Storage) * * Data Validation * * Auditing and Logging * * Error & Exception Handling * * User Management * *
Configuration Management  ASP.NET application running in  partial trust Revert.ToSelf(); Implementation Bug Design Flaw * good at many web server config issues Web App Scanners Hard coded connection string in configuration files Use of common crypto keys across Implemntations Hosted Environment
Data Validation Implementation Bug Design Flaw Web App Scanners Canonicalization Internationalization Stored cross site scripting (even basic XSS in some cases) SQL injection (non ‘) Buffer overflows NOT HTTP 500’s! * Their strongest category
Data protection Implementation Bug Design Flaw Web App Scanners Clear text passwords stored  in database Weak algorithms * Reusing keys with stream ciphers Weak random number generators Secure memory management issues
User Management Clear text passwords in  the database Password expiry Password reset sent in clear Implementation Bug Design Flaw Web App Scanners Password generation on reset Weak session ID’s
Grep: Lack of Context … strcpy(dst, src);  // Generally a “high severity” error … strncpy(dst, src); // Generally a filtered out “low sev” …
Grep: Lack of Context … // Generally a “high severity” error strcpy(dst, src);  // Generally a “high severity” error … // Generally “low severity”, filtered out by default strncpy(dst, src, n);  …
Grep: Lack of Context void copy_20(char *src) { char dst[20]; int  n; if (strlen(src) > 19) { return 0; } strcpy(dst, src);  return strdup(dst); }
Grep: Lack of Context void copy(char *dst, char *src) { int  n = strlen(src); strncpy(dst, src, n);  return strdup(dst); } … char d[20]; copy(d, arbitrary_user_input);
Grep-style Cons: 95%+ false positives for most apps False negatives when rules ignore API while(i<n) buf[i++] = getc(); Reports: char crlf[]=“\r\n”; strcat(“foo”, crlf); Pros: Gives manual auditor a starting point Easy to support new languages Immediate results on any code base
Let’s try to do better with “real” static analysis!
 
Sample program void main(int argc, char **argv) { char b1[100] = {0,};  // alloc(B1) <- 100 char b2[100] = {0,};  // alloc(B2) <- 100 char b3[100] = {0,};  // alloc(B3) <- 100 strcpy(b2, b1);  // len(B2)<-len(B1)<- 100; No error. if (argc > 1) {  // len(B3) <- max(len(argv), 400) strncpy(b3, argv[1], 400);  // alloc(B3) == 100. // len > alloc: ERROR! }
Another program // alloc(ARGV) <- len(ARGV) <- [0,MAX] void main(int argc, char **argv) {  char *b1 = malloc(100);  // alloc(B1) <- [100,100] char *b2 = malloc(100);  // alloc(B2) <- [100,100] int  i; strcpy(b2, “foo”); //  len(B2) <- 4 if (argc > 1 && strlen(argv[1]) < 100) strcpy(b1, argv[1]);  // len(B1) <- len(ARGV) for (i=0;i<3;i++)  // i <- i + 1 strcat(b2, “.”);  // len(B2) <- len(B2) + 1 }
alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,0] alloc(B2) [100,100] len(B2) [0,0] 4 len(ARGV)  -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,0] alloc(B2) [100,100] len(B2) [0,0] 4 len(ARGV)  -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,0] 4 len(ARGV)  -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,1] 4 len(ARGV)  -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,1] 4 len(ARGV)  -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,max] 4 len(ARGV)  -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,max] 4 len(ARGV)  -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,max] 4 len(ARGV)  -> len(B1) len(B2) -> len(B2) + 1 i [0,max] i <- i + 1
alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,max] Okay: no incoming edges to len(ARGV) RANGE OVERLAPS: B1 MAY OVERFLOW RANGE OVERLAPS: B2 MAY OVERFLOW
The Program Again void main(int argc, char **argv) {  char *b1 = malloc(100);  char *b2 = malloc(100); int  i; strcpy(b2, “foo”);  if (argc > 1 && strlen(argv[1]) < 100) strcpy(b1, argv[1]);  for (i=0;i<3;i++) strcat(b2, “.”); } Is this the b2 vuln?
The Program Again void main(int argc, char **argv) {  char *b1 = malloc(100);  char *b2 = malloc(100); int  i; strcpy(b2, “foo”);  if (argc > 1 && strlen(argv[1]) < 100) strcpy(b1, argv[1]);  for (i=0;i<3;i++) strcat(b2, “.”); } Or is this?
The Program Again void main(int argc, char **argv) {  char *b1 = malloc(100);  char *b2 = malloc(100); int  i; strcpy(b2, “foo”);  // b1 will never be less than 100. if (argc > 1 && strlen(argv[1]) < 100) strcpy(b1, argv[1]);   for (i=0;i<3;i++) strcat(b2, “.”); }
A good analysis requires some understanding of control flow!
Many analyses aren’t worth it! Over Grep: No great improvement in false positives Parsing code well is extremely complex Perl, anyone? In general: Capturing semantics is never-ending Specify 3 rd -party libraries, etc?
Control Flow #define len(x) strlen(x) void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max]  others: nil
Control Flow void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max]  others: nil alloc(b): 100
Control Flow void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max]  others: nil alloc(b): 100 len(b): 4
Control Flow void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max]  others: nil Write to B.  Does it overflow? alloc(b): 100 len(b): 4
Control Flow void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max]  others: nil No.  At this node, B is alloc’d to 100, actual len of 4. alloc(b): 100 len(b): 4
Control Flow B: alloc(100) B: len(4) void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max]  others: nil
Control Flow void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } True False Entry argc: [0,max]  others: nil alloc(b): 100 len(b): 4
Control Flow argc: [2, max] Entry argc: [0,max]  others: nil void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if( argc > 1  && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } True False alloc(b): 100 len(b): 4
Control Flow argc: [2, max] len(argv): [0, 100] alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 &&  len(argv[1]) < 100 ) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } True False
Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]
Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]  No overflow.  b is alloc’d to 100, len can be no more than 100 after null is added.
Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for ( i=0 ;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0
Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0 len(b): [0, 100] Use the worst case assumption for the length of b.
Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0 len(b): [0, 100] len(b): [0, 101]
Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil void main(int argc, char **argv) {  char *b = malloc(100);  int  i; strcpy(b, “foo”);  if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]);  for (i=0;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0 len(b): [0, 100] len(b): [0, 101] ERROR:  len(b) > alloc(b)!!!
Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0 len(b): [0, 100] len(b): [0, 101] Could show you the graph to help you debug…
Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0 len(b): [0, 100] len(b): [0, 101] If you’re a rocket scientist   (graphs get big and complex in real programs)
Control Flow foo.c:2412: example(): Possible buffer overflow of variable dst Stack trace: foo.c:1733: process_data() network.c:432: read_from_socket() main.c:94: main_loop() main.c:32: main() Though, we could show you (one possible) “stack trace” instead… (far better than dynamic analysis tools!)
Control Flow foo.c:2412: example(): Possible buffer overflow of variable dst Data trace: foo.c:1733: process_data() network.c:432: read_from_socket() | |->  Data received from external socket Or, we could show where the data came from
Not just memory stuff… SQL Injection error: WebGoat/src/lessons/ lessons.ChallengeScreen.doStage2 line 183 Source argument: query Potential unsafe contents: *;’&\ Input source: Network Data: lessons.ChallengeScreen.doStage2 line 178
Issue 1 void main(int argc, char **argv) {  char *b = malloc( 100000 );  int  n = argc; for (i=0;i<n;i++) strcat(b, “.”); }
Issue 1 void main(int argc, char **argv) {  char *b = malloc(100000);  int  n = argc; for (i=0;i<n;i++) strcat(b, “.”); } In a more complex example, would we really have to “run” the loop MAX_INT times?
Issue 1 void main(int argc, char **argv) {  char *b = malloc(100000);  int  n = argc; for (i=0;i<n;i++) strcat(b, “.”); } In this case, we could multiply the effect by the maximum value of n.
Issue 1 void main(int argc, char **argv) {  char *b = malloc(100000);  int  n = argc; for (i=0;i<n;i++) strcat(b, “.”); } More complex cases aren’t that easy, and require approximations!
Issue 2 alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0 len(b): [0, 100] We lost accuracy when we merged.
Issue 2 alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0 len(b): [0, 101] i = 0 len(b): 4
Issue 2 alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0 We can show which path is bad! And, future calculations become much more accurate. len(b): [0, 101] i = 0 len(b): 4
Issue 2 alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0 len(b): [0, 101] i = 0 len(b): 4 An exponential explosion of nodes Only feasible for single functions (intraprocedural analysis)
Issue 2 alloc(b): 100 len(b): 4 Entry argc: [0,max]  others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]   i = 0 len(b): [0, 101] i = 0 len(b): 4 Full path analysis is even less feasible when we consider exits from complex loops
The problem with intraprocedural char *magic_function(char *a, char *b) { char *p1 = a; char *p2 = b; while (*p2) *p1++ = *p2++; return a; }
The problem with intraprocedural char *magic_function(char *a, char *b) { char *p1 = a; char *p2 = b; while (*p2) *p1++ = *p2++; return a; } No matter how accurate we get inside the procedure, we are in a catch-22 (spam vs. ignore)
The problem with intraprocedural char *magic_function(char *a, char *b) { char *p1 = a; char *p2 = b; while (*p2) *p1++ = *p2++; return a; } Instead of erroring, we can “summarize” the generic properties.
The problem with intraprocedural char *magic_function(char *a, char *b) { char *p1 = a; char *p2 = b; while (*p2) *p1++ = *p2++; return a; } e.g., len(a) <- len(b)
The problem with intraprocedural char *magic_function(char *a, char *b) { char *p1 = a; char *p2 = b; while (*p2) *p1++ = *p2++; return a; } Scaling algorithms to an entire program can greatly improve accuracy… and decrease efficiency!
Using environmental knowledge Socket vs. file Consider data from config files / registry Analyze two communicating programs together
There will always be falses For some things, even false negatives e.g., anything in C Lots of things need to be approximated and are tough to approximate well Arrays and pointers Dynamic dispatch Built in containers Okay, it’s an overflow, but is it exploitable? Do you care?
Building good tools is hard! Good analysis takes years Most companies haven’t bothered to try! Tool should handle all dev environments efficiency + checkins? Tools should be easy enough for my mom Binary analysis is far, far harder! Few people do even a reasonable job.
Everybody gets this right… for the wrong reasons secureConnect (host, port): s = sslConnect(gethostbyaddr(host), port) cert = get_cert(s) if ! certSignedByTrustedRoot(cert): raise “SSLError” if  cert.DN <> host: raise “SSLError” if ! subjAltNameMatches(cert, host): raise “SSLError” if certRevoked(cert): raise “SSLError” return s
If you’re not an auditor, it probably isn’t cost effective!
Notes on Buying Automated Tools Trials are limited for a reason (as are the EULA’s) Make sure you test them on your own site / code
“ The height of mediocrity is still low” Basic Conclusion
Accuracy on basic software today is mediocre at best It is really easy to write an application that can’t be automatically scanned It is really hard to write an automated scanner than can effectively analyze software Basic Conclusion
 
PCI Data Security Standards
 
6.6 Ensure that all web-facing applications are protected against known  attacks by applying either of the following methods:  •  Having all custom application code reviewed for  common vulnerabilities  by an  organization that specializes in application security  •  Installing an  application layer firewall  in front of web-facing applications.    Note: This method is considered a best practice until June 30, 2008,  after which it becomes a requirement.    Full document at  https://www.pcisecuritystandards.org/tech/download_the_pci_dss.htm PCI-DSS is now managed by an industry consortium at  www.pcisecuritystandards.org
…… or go straight to the document here! https://www.pcisecuritystandards.org/pdfs/pci_dss_v1-1.pdf
 
Introducing the only tool in the world that really works effectively today……
 
News for people who run tools
A fool with a tool … .is still a fool
China!
China!
China!
People Process Technology
Fair and Balance Automated tools aren’t totally “useless” today (* but the marketing departments cards are marked)
What sort of tool do we want? Testing framework / toolkit that combines Binary Run-time Code Pen AI (or human driven) Extensible Community driven rules
 
That’s all folks!

More Related Content

PPTX
riscos tipicos no SEP.pptx
PPT
Aula 07 fisiologia - mecanismos da respiração
DOCX
Upstream B2 Worksheet Units 1+2+3
PDF
4 solutions intermediate_student_s_book
PDF
1.Buffer Overflows
PDF
2 buffer overflows
PPT
Buffer OverFlow
PPT
Buffer Overflows
riscos tipicos no SEP.pptx
Aula 07 fisiologia - mecanismos da respiração
Upstream B2 Worksheet Units 1+2+3
4 solutions intermediate_student_s_book
1.Buffer Overflows
2 buffer overflows
Buffer OverFlow
Buffer Overflows

Similar to Hack in the Box Keynote 2006 (20)

PPT
Automatically Tolerating And Correcting Memory Errors
PPT
6 buffer overflows
PDF
Ch 18: Source Code Auditing
PPT
DieHard: Probabilistic Memory Safety for Unsafe Languages
PPTX
Static analysis of C++ source code
PPTX
Static analysis of C++ source code
PPTX
C programming
PDF
software-vulnerability-detectionPresentation
DOC
C - aptitude3
DOC
C aptitude questions
PDF
Presentation buffer overflow attacks and theircountermeasures
PDF
printf tricks
PPTX
Virtual Separation of Concerns (2011 Update)
PDF
Software Security
PDF
Secure Coding Practices for Middleware
PPT
Software(runtime) attacks
PDF
StackOverflow
PDF
CNIT 127: Ch 18: Source Code Auditing
PDF
Fuzzing - Part 1
PPT
When good code goes bad
Automatically Tolerating And Correcting Memory Errors
6 buffer overflows
Ch 18: Source Code Auditing
DieHard: Probabilistic Memory Safety for Unsafe Languages
Static analysis of C++ source code
Static analysis of C++ source code
C programming
software-vulnerability-detectionPresentation
C - aptitude3
C aptitude questions
Presentation buffer overflow attacks and theircountermeasures
printf tricks
Virtual Separation of Concerns (2011 Update)
Software Security
Secure Coding Practices for Middleware
Software(runtime) attacks
StackOverflow
CNIT 127: Ch 18: Source Code Auditing
Fuzzing - Part 1
When good code goes bad

More from Mark Curphey (12)

PDF
Curphey AppSecUSA - Community The Killer Application
PPT
Software Security in the Real World
PPT
Research
PPT
Product Definition
PPT
Product and Brand
PPT
Product Positioning and Lifecycle
PPT
New product Offer
PPT
Marketing Introduction
PPT
Advertising Theory
PPT
Innovators Dilemma Slides
PPT
Managing Corporate Information Security Risk in Financial Institutions
PPT
Naked Security
Curphey AppSecUSA - Community The Killer Application
Software Security in the Real World
Research
Product Definition
Product and Brand
Product Positioning and Lifecycle
New product Offer
Marketing Introduction
Advertising Theory
Innovators Dilemma Slides
Managing Corporate Information Security Risk in Financial Institutions
Naked Security

Recently uploaded (20)

PDF
1911 Gold Corporate Presentation Aug 2025.pdf
PPTX
operations management : demand supply ch
DOCX
Handbook of Entrepreneurship- Chapter 5: Identifying business opportunity.docx
PPTX
svnfcksanfskjcsnvvjknsnvsdscnsncxasxa saccacxsax
PDF
Technical Architecture - Chainsys dataZap
DOCX
80 DE ÔN VÀO 10 NĂM 2023vhkkkjjhhhhjjjj
PPTX
basic introduction to research chapter 1.pptx
PDF
NISM Series V-A MFD Workbook v December 2024.khhhjtgvwevoypdnew one must use ...
PDF
Cours de Système d'information about ERP.pdf
PDF
Keppel_Proposed Divestment of M1 Limited
PDF
PMB 401-Identification-of-Potential-Biotechnological-Products.pdf
PPTX
Project Management_ SMART Projects Class.pptx
PDF
Solaris Resources Presentation - Corporate August 2025.pdf
PDF
Tortilla Mexican Grill 发射点犯得上发射点发生发射点犯得上发生
PDF
Introduction to Generative Engine Optimization (GEO)
PDF
Digital Marketing & E-commerce Certificate Glossary.pdf.................
PDF
TyAnn Osborn: A Visionary Leader Shaping Corporate Workforce Dynamics
PDF
NEW - FEES STRUCTURES (01-july-2024).pdf
PPTX
Astra-Investor- business Presentation (1).pptx
PPTX
Board-Reporting-Package-by-Umbrex-5-23-23.pptx
1911 Gold Corporate Presentation Aug 2025.pdf
operations management : demand supply ch
Handbook of Entrepreneurship- Chapter 5: Identifying business opportunity.docx
svnfcksanfskjcsnvvjknsnvsdscnsncxasxa saccacxsax
Technical Architecture - Chainsys dataZap
80 DE ÔN VÀO 10 NĂM 2023vhkkkjjhhhhjjjj
basic introduction to research chapter 1.pptx
NISM Series V-A MFD Workbook v December 2024.khhhjtgvwevoypdnew one must use ...
Cours de Système d'information about ERP.pdf
Keppel_Proposed Divestment of M1 Limited
PMB 401-Identification-of-Potential-Biotechnological-Products.pdf
Project Management_ SMART Projects Class.pptx
Solaris Resources Presentation - Corporate August 2025.pdf
Tortilla Mexican Grill 发射点犯得上发射点发生发射点犯得上发生
Introduction to Generative Engine Optimization (GEO)
Digital Marketing & E-commerce Certificate Glossary.pdf.................
TyAnn Osborn: A Visionary Leader Shaping Corporate Workforce Dynamics
NEW - FEES STRUCTURES (01-july-2024).pdf
Astra-Investor- business Presentation (1).pptx
Board-Reporting-Package-by-Umbrex-5-23-23.pptx

Hack in the Box Keynote 2006

  • 1. What application security tools vendors don’t want you to know and holes they will never find! Mark Curphey John Viega
  • 2.  
  • 3.  
  • 4.  
  • 5.  
  • 6.  
  • 7.  
  • 8.  
  • 9.  
  • 10.  
  • 11.  
  • 12.  
  • 13.  
  • 14.  
  • 15.  
  • 16.  
  • 17.  
  • 18.  
  • 19.  
  • 20.  
  • 21.  
  • 22.  
  • 23.  
  • 24.  
  • 25.  
  • 26.  
  • 27.  
  • 28.  
  • 29.  
  • 30.  
  • 31.  
  • 32.  
  • 33.  
  • 34.  
  • 35.  
  • 36.  
  • 37.  
  • 38.  
  • 39.  
  • 40.  
  • 41.  
  • 42. How Important is Context?
  • 43.  
  • 44.  
  • 45.  
  • 46.  
  • 47. Mozilla vs. Klocwork 611 “defects” 72 “vulnerabilities” 3 verified bugs 99.5% useless?
  • 48.  
  • 49.  
  • 50.  
  • 51. What kind of talk is this? Tools that try to find security holes in software Way for us to understand and rationalize why they are so bad and unlikely to get much better soon It is a realistic state of the union about the current state of application security technology and how it is being marketed and applied Dr. Holger Peine http://fhgonline.fraunhofer.de/server?suche-publica&num=048.06/D&iese (N.B. about overly generous quote to Cenzic) Arian Evans http://www.owasp.org/index.php/Image:AppSec2005DC-Arian_Evans_Tools-Taxonomy.ppt
  • 52. New Topic How software is built in the real world Security Reference Frame Types of Tools What They Realistically Find
  • 53.  
  • 54.  
  • 55.  
  • 56. How is security built in the real world?
  • 57.  
  • 58.  
  • 59.  
  • 60. How is security built in the real world?
  • 61. How is security built in the real world?
  • 62.  
  • 63. Implementation Bugs vs. Design Flaws
  • 64. Security Frame of Reference Name Description Configuration Management Configs, security managers, web server settings etc. Authentication Knowing users and entities are who they claim to be Authorization Who can do what to whom, TOCTOU etc. Data Protection (Transit & Storage) Encrypted passwords, on-wire protection, channel sinks, encrypted configuration files etc. Data Validation Valid, well formed, free of malicious payloads etc. Auditing and Logging Knowing who does what to whom etc. Error & Exception Handling What happens when the pooh hits the fan etc. User Management Password reset, registration, licensing etc.
  • 65.  
  • 66. Scorecard * unscientific, based on experience stands reasonable chance of finding issues “ could” find some issues unlikely to find issues with confidence Security Reference Frame Effectiveness of Assessment Tools Web App Scanners Static Code Analysis Binary Analysis Bug Flaw Bug Flaw Bug Flaw Configuration Management * * Authentication * * Authorization * * Data Protection (Transit & Storage) * * Data Validation * * Auditing and Logging * * Error & Exception Handling * * User Management * *
  • 67. Configuration Management ASP.NET application running in partial trust Revert.ToSelf(); Implementation Bug Design Flaw * good at many web server config issues Web App Scanners Hard coded connection string in configuration files Use of common crypto keys across Implemntations Hosted Environment
  • 68. Data Validation Implementation Bug Design Flaw Web App Scanners Canonicalization Internationalization Stored cross site scripting (even basic XSS in some cases) SQL injection (non ‘) Buffer overflows NOT HTTP 500’s! * Their strongest category
  • 69. Data protection Implementation Bug Design Flaw Web App Scanners Clear text passwords stored in database Weak algorithms * Reusing keys with stream ciphers Weak random number generators Secure memory management issues
  • 70. User Management Clear text passwords in the database Password expiry Password reset sent in clear Implementation Bug Design Flaw Web App Scanners Password generation on reset Weak session ID’s
  • 71. Grep: Lack of Context … strcpy(dst, src); // Generally a “high severity” error … strncpy(dst, src); // Generally a filtered out “low sev” …
  • 72. Grep: Lack of Context … // Generally a “high severity” error strcpy(dst, src); // Generally a “high severity” error … // Generally “low severity”, filtered out by default strncpy(dst, src, n); …
  • 73. Grep: Lack of Context void copy_20(char *src) { char dst[20]; int n; if (strlen(src) > 19) { return 0; } strcpy(dst, src); return strdup(dst); }
  • 74. Grep: Lack of Context void copy(char *dst, char *src) { int n = strlen(src); strncpy(dst, src, n); return strdup(dst); } … char d[20]; copy(d, arbitrary_user_input);
  • 75. Grep-style Cons: 95%+ false positives for most apps False negatives when rules ignore API while(i<n) buf[i++] = getc(); Reports: char crlf[]=“\r\n”; strcat(“foo”, crlf); Pros: Gives manual auditor a starting point Easy to support new languages Immediate results on any code base
  • 76. Let’s try to do better with “real” static analysis!
  • 77.  
  • 78. Sample program void main(int argc, char **argv) { char b1[100] = {0,}; // alloc(B1) <- 100 char b2[100] = {0,}; // alloc(B2) <- 100 char b3[100] = {0,}; // alloc(B3) <- 100 strcpy(b2, b1); // len(B2)<-len(B1)<- 100; No error. if (argc > 1) { // len(B3) <- max(len(argv), 400) strncpy(b3, argv[1], 400); // alloc(B3) == 100. // len > alloc: ERROR! }
  • 79. Another program // alloc(ARGV) <- len(ARGV) <- [0,MAX] void main(int argc, char **argv) { char *b1 = malloc(100); // alloc(B1) <- [100,100] char *b2 = malloc(100); // alloc(B2) <- [100,100] int i; strcpy(b2, “foo”); // len(B2) <- 4 if (argc > 1 && strlen(argv[1]) < 100) strcpy(b1, argv[1]); // len(B1) <- len(ARGV) for (i=0;i<3;i++) // i <- i + 1 strcat(b2, “.”); // len(B2) <- len(B2) + 1 }
  • 80. alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,0] alloc(B2) [100,100] len(B2) [0,0] 4 len(ARGV) -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
  • 81. alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,0] alloc(B2) [100,100] len(B2) [0,0] 4 len(ARGV) -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
  • 82. alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,0] 4 len(ARGV) -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
  • 83. alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,1] 4 len(ARGV) -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
  • 84. alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,1] 4 len(ARGV) -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
  • 85. alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,max] 4 len(ARGV) -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
  • 86. alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,max] 4 len(ARGV) -> len(B1) len(B2) -> len(B2) + 1 i [0,0] i <- i + 1
  • 87. alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,max] 4 len(ARGV) -> len(B1) len(B2) -> len(B2) + 1 i [0,max] i <- i + 1
  • 88. alloc(ARGV) [0,max] alloc(B1) [100,100] len(ARGV) [0,max] len(B1) [0,max] alloc(B2) [100,100] len(B2) [0,max] Okay: no incoming edges to len(ARGV) RANGE OVERLAPS: B1 MAY OVERFLOW RANGE OVERLAPS: B2 MAY OVERFLOW
  • 89. The Program Again void main(int argc, char **argv) { char *b1 = malloc(100); char *b2 = malloc(100); int i; strcpy(b2, “foo”); if (argc > 1 && strlen(argv[1]) < 100) strcpy(b1, argv[1]); for (i=0;i<3;i++) strcat(b2, “.”); } Is this the b2 vuln?
  • 90. The Program Again void main(int argc, char **argv) { char *b1 = malloc(100); char *b2 = malloc(100); int i; strcpy(b2, “foo”); if (argc > 1 && strlen(argv[1]) < 100) strcpy(b1, argv[1]); for (i=0;i<3;i++) strcat(b2, “.”); } Or is this?
  • 91. The Program Again void main(int argc, char **argv) { char *b1 = malloc(100); char *b2 = malloc(100); int i; strcpy(b2, “foo”); // b1 will never be less than 100. if (argc > 1 && strlen(argv[1]) < 100) strcpy(b1, argv[1]); for (i=0;i<3;i++) strcat(b2, “.”); }
  • 92. A good analysis requires some understanding of control flow!
  • 93. Many analyses aren’t worth it! Over Grep: No great improvement in false positives Parsing code well is extremely complex Perl, anyone? In general: Capturing semantics is never-ending Specify 3 rd -party libraries, etc?
  • 94. Control Flow #define len(x) strlen(x) void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max] others: nil
  • 95. Control Flow void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max] others: nil alloc(b): 100
  • 96. Control Flow void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max] others: nil alloc(b): 100 len(b): 4
  • 97. Control Flow void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max] others: nil Write to B. Does it overflow? alloc(b): 100 len(b): 4
  • 98. Control Flow void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max] others: nil No. At this node, B is alloc’d to 100, actual len of 4. alloc(b): 100 len(b): 4
  • 99. Control Flow B: alloc(100) B: len(4) void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } Entry argc: [0,max] others: nil
  • 100. Control Flow void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } True False Entry argc: [0,max] others: nil alloc(b): 100 len(b): 4
  • 101. Control Flow argc: [2, max] Entry argc: [0,max] others: nil void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if( argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } True False alloc(b): 100 len(b): 4
  • 102. Control Flow argc: [2, max] len(argv): [0, 100] alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100 ) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } True False
  • 103. Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100]
  • 104. Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] No overflow. b is alloc’d to 100, len can be no more than 100 after null is added.
  • 105. Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for ( i=0 ;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0
  • 106. Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0 len(b): [0, 100] Use the worst case assumption for the length of b.
  • 107. Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0 len(b): [0, 100] len(b): [0, 101]
  • 108. Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil void main(int argc, char **argv) { char *b = malloc(100); int i; strcpy(b, “foo”); if(argc > 1 && len(argv[1]) < 100) strcpy(b, argv[1]); for (i=0;i<3;i++) strcat(b, “.”); } True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0 len(b): [0, 100] len(b): [0, 101] ERROR: len(b) > alloc(b)!!!
  • 109. Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0 len(b): [0, 100] len(b): [0, 101] Could show you the graph to help you debug…
  • 110. Control Flow alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0 len(b): [0, 100] len(b): [0, 101] If you’re a rocket scientist  (graphs get big and complex in real programs)
  • 111. Control Flow foo.c:2412: example(): Possible buffer overflow of variable dst Stack trace: foo.c:1733: process_data() network.c:432: read_from_socket() main.c:94: main_loop() main.c:32: main() Though, we could show you (one possible) “stack trace” instead… (far better than dynamic analysis tools!)
  • 112. Control Flow foo.c:2412: example(): Possible buffer overflow of variable dst Data trace: foo.c:1733: process_data() network.c:432: read_from_socket() | |-> Data received from external socket Or, we could show where the data came from
  • 113. Not just memory stuff… SQL Injection error: WebGoat/src/lessons/ lessons.ChallengeScreen.doStage2 line 183 Source argument: query Potential unsafe contents: *;’&\ Input source: Network Data: lessons.ChallengeScreen.doStage2 line 178
  • 114. Issue 1 void main(int argc, char **argv) { char *b = malloc( 100000 ); int n = argc; for (i=0;i<n;i++) strcat(b, “.”); }
  • 115. Issue 1 void main(int argc, char **argv) { char *b = malloc(100000); int n = argc; for (i=0;i<n;i++) strcat(b, “.”); } In a more complex example, would we really have to “run” the loop MAX_INT times?
  • 116. Issue 1 void main(int argc, char **argv) { char *b = malloc(100000); int n = argc; for (i=0;i<n;i++) strcat(b, “.”); } In this case, we could multiply the effect by the maximum value of n.
  • 117. Issue 1 void main(int argc, char **argv) { char *b = malloc(100000); int n = argc; for (i=0;i<n;i++) strcat(b, “.”); } More complex cases aren’t that easy, and require approximations!
  • 118. Issue 2 alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0 len(b): [0, 100] We lost accuracy when we merged.
  • 119. Issue 2 alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0 len(b): [0, 101] i = 0 len(b): 4
  • 120. Issue 2 alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0 We can show which path is bad! And, future calculations become much more accurate. len(b): [0, 101] i = 0 len(b): 4
  • 121. Issue 2 alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0 len(b): [0, 101] i = 0 len(b): 4 An exponential explosion of nodes Only feasible for single functions (intraprocedural analysis)
  • 122. Issue 2 alloc(b): 100 len(b): 4 Entry argc: [0,max] others: nil True False argc: [2, max] len(argv): [0, 100] len(b): [0, 100] i = 0 len(b): [0, 101] i = 0 len(b): 4 Full path analysis is even less feasible when we consider exits from complex loops
  • 123. The problem with intraprocedural char *magic_function(char *a, char *b) { char *p1 = a; char *p2 = b; while (*p2) *p1++ = *p2++; return a; }
  • 124. The problem with intraprocedural char *magic_function(char *a, char *b) { char *p1 = a; char *p2 = b; while (*p2) *p1++ = *p2++; return a; } No matter how accurate we get inside the procedure, we are in a catch-22 (spam vs. ignore)
  • 125. The problem with intraprocedural char *magic_function(char *a, char *b) { char *p1 = a; char *p2 = b; while (*p2) *p1++ = *p2++; return a; } Instead of erroring, we can “summarize” the generic properties.
  • 126. The problem with intraprocedural char *magic_function(char *a, char *b) { char *p1 = a; char *p2 = b; while (*p2) *p1++ = *p2++; return a; } e.g., len(a) <- len(b)
  • 127. The problem with intraprocedural char *magic_function(char *a, char *b) { char *p1 = a; char *p2 = b; while (*p2) *p1++ = *p2++; return a; } Scaling algorithms to an entire program can greatly improve accuracy… and decrease efficiency!
  • 128. Using environmental knowledge Socket vs. file Consider data from config files / registry Analyze two communicating programs together
  • 129. There will always be falses For some things, even false negatives e.g., anything in C Lots of things need to be approximated and are tough to approximate well Arrays and pointers Dynamic dispatch Built in containers Okay, it’s an overflow, but is it exploitable? Do you care?
  • 130. Building good tools is hard! Good analysis takes years Most companies haven’t bothered to try! Tool should handle all dev environments efficiency + checkins? Tools should be easy enough for my mom Binary analysis is far, far harder! Few people do even a reasonable job.
  • 131. Everybody gets this right… for the wrong reasons secureConnect (host, port): s = sslConnect(gethostbyaddr(host), port) cert = get_cert(s) if ! certSignedByTrustedRoot(cert): raise “SSLError” if cert.DN <> host: raise “SSLError” if ! subjAltNameMatches(cert, host): raise “SSLError” if certRevoked(cert): raise “SSLError” return s
  • 132. If you’re not an auditor, it probably isn’t cost effective!
  • 133. Notes on Buying Automated Tools Trials are limited for a reason (as are the EULA’s) Make sure you test them on your own site / code
  • 134. “ The height of mediocrity is still low” Basic Conclusion
  • 135. Accuracy on basic software today is mediocre at best It is really easy to write an application that can’t be automatically scanned It is really hard to write an automated scanner than can effectively analyze software Basic Conclusion
  • 136.  
  • 137. PCI Data Security Standards
  • 138.  
  • 139. 6.6 Ensure that all web-facing applications are protected against known attacks by applying either of the following methods: • Having all custom application code reviewed for common vulnerabilities by an organization that specializes in application security • Installing an application layer firewall in front of web-facing applications.   Note: This method is considered a best practice until June 30, 2008, after which it becomes a requirement.   Full document at https://www.pcisecuritystandards.org/tech/download_the_pci_dss.htm PCI-DSS is now managed by an industry consortium at www.pcisecuritystandards.org
  • 140. …… or go straight to the document here! https://www.pcisecuritystandards.org/pdfs/pci_dss_v1-1.pdf
  • 141.  
  • 142. Introducing the only tool in the world that really works effectively today……
  • 143.  
  • 144. News for people who run tools
  • 145. A fool with a tool … .is still a fool
  • 146. China!
  • 147. China!
  • 148. China!
  • 150. Fair and Balance Automated tools aren’t totally “useless” today (* but the marketing departments cards are marked)
  • 151. What sort of tool do we want? Testing framework / toolkit that combines Binary Run-time Code Pen AI (or human driven) Extensible Community driven rules
  • 152.