SlideShare uma empresa Scribd logo
1 de 24
Time Tested PHP
Advanced testing techniques
   with libTimeMachine


      Nick Galbreath nickg@client9.com @ngalbreath
  Vince Tse vtonehundred@gmail.com @vtonehundred
                                           2012-07-19
Follow along or get the latest version at:




http://slidesha.re/
    NDc5mK
Time Happens
While it should be avoided as much as possible, sometimes
"time happens" and applications need testing based on
simulated time.

• Financial applications (e.g. simulating ad spending and
  budgeting)

• Security features (what happens when the cookie or auth
  token expires?)

• System testing (what happens on leap year? day light
  savings time? 2038?)

• Anything that runs periodically ("on the hour")
PHP Time Sources
• $_SERVER['REQUEST_TIME']

• time()

• microtime()

• gettimeofday()

• Single argument of date(fmt)
  (equivalent to date(fmt, time())
Using $_SERVER['REQUEST_TIME']


• Available in all SAPI contexts (mod_php, CLI, CGI, FPM...)

• Created once at time of request

• "Lowest Cost" -- array lookup

• Easy to spoof in unit tests

• Can't spoof for functional tests

• Can't use it for timing
Passing as Argument

• Don't call time() et al directly in a function
  but instead pass current time in.

• Allows unit testing

• Follows dependency injection best-practice
But what if your code
   isn't or can't be
structured that way?
Time Travel with
          libtimemachine!
https://github.com/vtonehundred/libtimemachine
     Changes the system calls that PHP uses to get the
     current time

        • time (defined in <time.h>)

        • gettimeofday (defined in <sys/time.h>)

        • clock_gettime (defined in <time.h>)

     and allows you to change them backwards or
     forward, relative or absolute.
LibTimeMachine
• Use some secret loader sexiness to change the
  underlying system calls.
   (see 'man ld-linux' for details)

• Works on Linux systems

• Works on Mac OS X (only tested on 10.7.4)

• Sorry Windows

• (not sure about FreeBSD)
Plug and Play
git clone 
git://github.com/vtonehundred/libtimemachine.git

cd libtimemachine

make

sudo cp libtimemachine.so [ /lib64 or /lib ]

sudo ldconfig
To use!
• libtimemachine reads /tmp/libtimemachine.conf
  (or whatever file you want using the
  LIBTIMEMACHINE_CONF environment variable)

• Single number controls how to adjust time

• If starts with "-" or "+" then current time will be adjusted
  by a relative amount.

• If "just numbers" then the time is fixed with this value

• If "0" or missing, then use current time
PHP CLI
Just add LD_PRELOAD=libtimemachine.so
before php on the command line
$ php -r 'echo date("rn");'
Mon, 28 May 2012 23:03:38 -0400

$ # go back one year
$ echo "-31536000" > /tmp/libtimemachine.conf

$ LD_PRELOAD=libtimemachine.so 
                   php -r 'echo date("rn");'
Sun, 29 May 2011 23:03:49 -0400

$ #winning
PHP 5.4 Built-In WebServer
                This is the easiest way to go!
$ date
Mon May 28 23:27:19 2012
$ echo "31536000" > /tmp/libtimemachine.conf
$ LD_PRELOAD=/lib64/libtimemachine.so 
           ./php -t ~/root -S 127.0.0.1:80
PHP 5.4.3 Development Server started at Tue May 28 23:29:19 2013
Listening on 127.0.0.1:80
Document root is ~/root
Press Ctrl-C to quit.
[Tue May 28 23:29:22 2013] 127.0.0.1:34913 [200]: ~/time.php


             Command line CGI works similarly
Apache mod_php
      Debian / Ubuntu
• Install libtimemachine.so in /lib64 or /
  lib depending on your OS.

• (for good measure also do "sudo ldconfig")

• /etc/apache2/envvars controls the
 apache and workers environment. Add
 export LD_PRELOAD=libtimemachine.so

• sudo /etc/init.d/apache2 restart
<?php
header('Content-Type: text/plain');
date_default_timezone_set('UTC'); //if you need it

printf("REQUEST_TIME   : %sn",
               date("r",$_SERVER['REQUEST_TIME']));
printf("time()         : %sn", date("r", time()));
printf("microtime()    : %sn", date("r", microtime(TRUE)));
printf("date('r')      : %sn", date("r"));
printf("gettimeofday() : %sn",
                date("r", gettimeofday(TRUE)));

//print_r($_SERVER);
Back One Day!
$ date
Sun, 27 May 2012 19:35:41 +0000

$ echo "-86400" > /tmp/libtimemachine.conf
$ curl 'http://127.0.0.1/phptime.php'
REQUEST_TIME     : Sat, 26 May 2012 19:35:54   +0000
time()           : Sat, 26 May 2012 19:35:54   +0000
microtime()      : Sat, 26 May 2012 19:35:54   +0000
date('r')        : Sat, 26 May 2012 19:35:54   +0000
gettimeofday()   : Sat, 26 May 2012 19:35:54   +0000
apache mod_php
        RedHat/CentOS
• Disable SELinux: in /etc/selinux/config set
  SELINUX=disabled

• put libtimemachine.so in /lib64 or /lib
  depending on your OS.

• (for good measure also do "sudo ldconfig")

• add to /etc/sysconfig/httpd
  export LD_PRELOAD=libtimemachine.so

• And then...
Fail on Apache +
mod_php + CentOS 6.2
• SELinux removes LD_PRELOAD

• Even though we disabled SELinux, it appears the linker
  isn't getting LD_PRELOAD

• mod_php is an shared library that loads shared
  libraries. hmmm

• I suspect a bug in the OS? Or maybe mod_php is
  compiled differently.

• Use PHP 5.4's built-in web server instead for testing.
Future Work
• Apache + PHP CGI (does anyone do this?)

• nginx + PHP FPM (the new hotness)

• Figuring out what is going on with CentOS

• Testing on mysql server.

• Packaging
Detecting
          libtimemachine
• Look for existence of
  /tmp/libtimemachine.conf

• Shell out and use "date +%s"
  and compare to time()

• Use Apache mod_env and add
  PassEnv LD_PRELOAD
  to let PHP see the environment variable
Evil

• Can this technique be used for evil?

• Oh yeah.

• type "LD_PRELOAD rootkit" in your favorite
  search engine for details
Mac OS X Notes
• Only tested on 10.7.4

• Mac OS X uses dyld for linking and works different than
  gnu ld. See 'man dyld' for details.

• Instead of LD_PRELOAD, use:
  DYLD_INSERT_LIBRARIES=./libtimemachine.dylib

• If that doesn't work, add
  DYLD_FORCE_FLAT_NAMESPACE=1
Gotchas
• if you globally set LD_PRELOAD,
 export LD_PRELOAD=libtimemachine.so
 then everything you do might be time shifted
 (to undo 'unset LD_PRELOAD')

• Your application might run a bit slower since
  every time lookup requires reading
   /tmp/libtimemachine.conf
Thanks!


https://github.com/vtonehundred/libtimemachine

       Nick Galbreath nickg@client9.com @ngalbreath
     Vince Tse vtonehundred@gmail.com @vtonehundred

Mais conteúdo relacionado

Mais procurados

Quay 3.3 installation
Quay 3.3 installationQuay 3.3 installation
Quay 3.3 installationJooho Lee
 
Ansible 2.0 - How to use Ansible to automate your applications in AWS.
Ansible 2.0 - How to use Ansible to automate your applications in AWS.Ansible 2.0 - How to use Ansible to automate your applications in AWS.
Ansible 2.0 - How to use Ansible to automate your applications in AWS.Idan Tohami
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...Tom Croucher
 
JavaScript Engines and Event Loop
JavaScript Engines and Event Loop JavaScript Engines and Event Loop
JavaScript Engines and Event Loop Tapan B.K.
 
Scaling Next-Generation Internet TV on AWS With Docker, Packer, and Chef
Scaling Next-Generation Internet TV on AWS With Docker, Packer, and ChefScaling Next-Generation Internet TV on AWS With Docker, Packer, and Chef
Scaling Next-Generation Internet TV on AWS With Docker, Packer, and Chefbridgetkromhout
 
Ansible - Swiss Army Knife Orchestration
Ansible - Swiss Army Knife OrchestrationAnsible - Swiss Army Knife Orchestration
Ansible - Swiss Army Knife Orchestrationbcoca
 
Using Ansible Dynamic Inventory with Amazon EC2
Using Ansible Dynamic Inventory with Amazon EC2Using Ansible Dynamic Inventory with Amazon EC2
Using Ansible Dynamic Inventory with Amazon EC2Brian Schott
 
The Good Parts / The Hard Parts
The Good Parts / The Hard PartsThe Good Parts / The Hard Parts
The Good Parts / The Hard PartsNoah Zoschke
 
Everything you wanted to know about writing async, concurrent http apps in java
Everything you wanted to know about writing async, concurrent http apps in java Everything you wanted to know about writing async, concurrent http apps in java
Everything you wanted to know about writing async, concurrent http apps in java Baruch Sadogursky
 
PyCon US 2012 - Web Server Bottlenecks and Performance Tuning
PyCon US 2012 - Web Server Bottlenecks and Performance TuningPyCon US 2012 - Web Server Bottlenecks and Performance Tuning
PyCon US 2012 - Web Server Bottlenecks and Performance TuningGraham Dumpleton
 
NginX - good practices, tips and advanced techniques
NginX - good practices, tips and advanced techniquesNginX - good practices, tips and advanced techniques
NginX - good practices, tips and advanced techniquesClaudio Borges
 
Ansible for beginners ...?
Ansible for beginners ...?Ansible for beginners ...?
Ansible for beginners ...?shirou wakayama
 
Install apache on centos
Install apache on centosInstall apache on centos
Install apache on centoshengko
 
Ansible with AWS
Ansible with AWSAnsible with AWS
Ansible with AWSAllan Denot
 
Config managament for development environments ii
Config managament for development environments iiConfig managament for development environments ii
Config managament for development environments iiGareth Rushgrove
 

Mais procurados (20)

Quay 3.3 installation
Quay 3.3 installationQuay 3.3 installation
Quay 3.3 installation
 
Ansible 2.0 - How to use Ansible to automate your applications in AWS.
Ansible 2.0 - How to use Ansible to automate your applications in AWS.Ansible 2.0 - How to use Ansible to automate your applications in AWS.
Ansible 2.0 - How to use Ansible to automate your applications in AWS.
 
Ansible
AnsibleAnsible
Ansible
 
A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...A language for the Internet: Why JavaScript and Node.js is right for Internet...
A language for the Internet: Why JavaScript and Node.js is right for Internet...
 
Scalable Web Apps
Scalable Web AppsScalable Web Apps
Scalable Web Apps
 
JavaScript Engines and Event Loop
JavaScript Engines and Event Loop JavaScript Engines and Event Loop
JavaScript Engines and Event Loop
 
Scaling Next-Generation Internet TV on AWS With Docker, Packer, and Chef
Scaling Next-Generation Internet TV on AWS With Docker, Packer, and ChefScaling Next-Generation Internet TV on AWS With Docker, Packer, and Chef
Scaling Next-Generation Internet TV on AWS With Docker, Packer, and Chef
 
Ansible - Swiss Army Knife Orchestration
Ansible - Swiss Army Knife OrchestrationAnsible - Swiss Army Knife Orchestration
Ansible - Swiss Army Knife Orchestration
 
Designing net-aws-glacier
Designing net-aws-glacierDesigning net-aws-glacier
Designing net-aws-glacier
 
Using Ansible Dynamic Inventory with Amazon EC2
Using Ansible Dynamic Inventory with Amazon EC2Using Ansible Dynamic Inventory with Amazon EC2
Using Ansible Dynamic Inventory with Amazon EC2
 
The Good Parts / The Hard Parts
The Good Parts / The Hard PartsThe Good Parts / The Hard Parts
The Good Parts / The Hard Parts
 
Everything you wanted to know about writing async, concurrent http apps in java
Everything you wanted to know about writing async, concurrent http apps in java Everything you wanted to know about writing async, concurrent http apps in java
Everything you wanted to know about writing async, concurrent http apps in java
 
PyCon US 2012 - Web Server Bottlenecks and Performance Tuning
PyCon US 2012 - Web Server Bottlenecks and Performance TuningPyCon US 2012 - Web Server Bottlenecks and Performance Tuning
PyCon US 2012 - Web Server Bottlenecks and Performance Tuning
 
NginX - good practices, tips and advanced techniques
NginX - good practices, tips and advanced techniquesNginX - good practices, tips and advanced techniques
NginX - good practices, tips and advanced techniques
 
Triple Blitz Strike
Triple Blitz StrikeTriple Blitz Strike
Triple Blitz Strike
 
Ansible for beginners ...?
Ansible for beginners ...?Ansible for beginners ...?
Ansible for beginners ...?
 
Install apache on centos
Install apache on centosInstall apache on centos
Install apache on centos
 
Ansible with AWS
Ansible with AWSAnsible with AWS
Ansible with AWS
 
Config managament for development environments ii
Config managament for development environments iiConfig managament for development environments ii
Config managament for development environments ii
 
Apache Cassandra and Go
Apache Cassandra and GoApache Cassandra and Go
Apache Cassandra and Go
 

Destaque

libinjection: a C library for SQLi detection, from Black Hat USA 2012
libinjection: a C library for SQLi detection, from Black Hat USA 2012libinjection: a C library for SQLi detection, from Black Hat USA 2012
libinjection: a C library for SQLi detection, from Black Hat USA 2012Nick Galbreath
 
libinjection: new technique in detecting SQLi attacks, iSEC Partners Open Forum
libinjection: new technique in detecting SQLi attacks, iSEC Partners Open Forumlibinjection: new technique in detecting SQLi attacks, iSEC Partners Open Forum
libinjection: new technique in detecting SQLi attacks, iSEC Partners Open ForumNick Galbreath
 
Program understanding: What programmers really want
Program understanding: What programmers really wantProgram understanding: What programmers really want
Program understanding: What programmers really wantEinar Høst
 
How to Leverage Log Data for Effective Threat Detection
How to Leverage Log Data for Effective Threat DetectionHow to Leverage Log Data for Effective Threat Detection
How to Leverage Log Data for Effective Threat DetectionAlienVault
 
Best Practices for Leveraging Security Threat Intelligence
Best Practices for Leveraging Security Threat IntelligenceBest Practices for Leveraging Security Threat Intelligence
Best Practices for Leveraging Security Threat IntelligenceAlienVault
 
IDS for Security Analysts: How to Get Actionable Insights from your IDS
IDS for Security Analysts: How to Get Actionable Insights from your IDSIDS for Security Analysts: How to Get Actionable Insights from your IDS
IDS for Security Analysts: How to Get Actionable Insights from your IDSAlienVault
 
How to Detect SQL Injections & XSS Attacks with AlienVault USM
How to Detect SQL Injections & XSS Attacks with AlienVault USM How to Detect SQL Injections & XSS Attacks with AlienVault USM
How to Detect SQL Injections & XSS Attacks with AlienVault USM AlienVault
 
libinjection: from SQLi to XSS  by Nick Galbreath
libinjection: from SQLi to XSS  by Nick Galbreathlibinjection: from SQLi to XSS  by Nick Galbreath
libinjection: from SQLi to XSS  by Nick GalbreathCODE BLUE
 
The promise of asynchronous PHP
The promise of asynchronous PHPThe promise of asynchronous PHP
The promise of asynchronous PHPWim Godden
 

Destaque (11)

libinjection: a C library for SQLi detection, from Black Hat USA 2012
libinjection: a C library for SQLi detection, from Black Hat USA 2012libinjection: a C library for SQLi detection, from Black Hat USA 2012
libinjection: a C library for SQLi detection, from Black Hat USA 2012
 
libinjection: new technique in detecting SQLi attacks, iSEC Partners Open Forum
libinjection: new technique in detecting SQLi attacks, iSEC Partners Open Forumlibinjection: new technique in detecting SQLi attacks, iSEC Partners Open Forum
libinjection: new technique in detecting SQLi attacks, iSEC Partners Open Forum
 
Program understanding: What programmers really want
Program understanding: What programmers really wantProgram understanding: What programmers really want
Program understanding: What programmers really want
 
How to Leverage Log Data for Effective Threat Detection
How to Leverage Log Data for Effective Threat DetectionHow to Leverage Log Data for Effective Threat Detection
How to Leverage Log Data for Effective Threat Detection
 
Best Practices for Leveraging Security Threat Intelligence
Best Practices for Leveraging Security Threat IntelligenceBest Practices for Leveraging Security Threat Intelligence
Best Practices for Leveraging Security Threat Intelligence
 
IDS for Security Analysts: How to Get Actionable Insights from your IDS
IDS for Security Analysts: How to Get Actionable Insights from your IDSIDS for Security Analysts: How to Get Actionable Insights from your IDS
IDS for Security Analysts: How to Get Actionable Insights from your IDS
 
How to Detect SQL Injections & XSS Attacks with AlienVault USM
How to Detect SQL Injections & XSS Attacks with AlienVault USM How to Detect SQL Injections & XSS Attacks with AlienVault USM
How to Detect SQL Injections & XSS Attacks with AlienVault USM
 
libinjection: from SQLi to XSS  by Nick Galbreath
libinjection: from SQLi to XSS  by Nick Galbreathlibinjection: from SQLi to XSS  by Nick Galbreath
libinjection: from SQLi to XSS  by Nick Galbreath
 
How To Detect Xss
How To Detect XssHow To Detect Xss
How To Detect Xss
 
Content security policy
Content security policyContent security policy
Content security policy
 
The promise of asynchronous PHP
The promise of asynchronous PHPThe promise of asynchronous PHP
The promise of asynchronous PHP
 

Semelhante a Time tested php with libtimemachine

Reutov, yunusov, nagibin random numbers take ii
Reutov, yunusov, nagibin   random numbers take iiReutov, yunusov, nagibin   random numbers take ii
Reutov, yunusov, nagibin random numbers take iiDefconRussia
 
How to automate all your SEO projects
How to automate all your SEO projectsHow to automate all your SEO projects
How to automate all your SEO projectsVincent Terrasi
 
php & performance
 php & performance php & performance
php & performancesimon8410
 
Charla EHU Noviembre 2014 - Desarrollo Web
Charla EHU Noviembre 2014 - Desarrollo WebCharla EHU Noviembre 2014 - Desarrollo Web
Charla EHU Noviembre 2014 - Desarrollo WebMikel Torres Ugarte
 
PHP & Performance
PHP & PerformancePHP & Performance
PHP & Performance毅 吕
 
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)Fabrice Bernhard
 
PHP Sessions and Non-Sessions
PHP Sessions and Non-SessionsPHP Sessions and Non-Sessions
PHP Sessions and Non-SessionsSven Rautenberg
 
Caching and tuning fun for high scalability
Caching and tuning fun for high scalabilityCaching and tuning fun for high scalability
Caching and tuning fun for high scalabilityWim Godden
 
Why and How Powershell will rule the Command Line - Barcamp LA 4
Why and How Powershell will rule the Command Line - Barcamp LA 4Why and How Powershell will rule the Command Line - Barcamp LA 4
Why and How Powershell will rule the Command Line - Barcamp LA 4Ilya Haykinson
 
PowerShell - Be A Cool Blue Kid
PowerShell - Be A Cool Blue KidPowerShell - Be A Cool Blue Kid
PowerShell - Be A Cool Blue KidMatthew Johnson
 
Drupal Efficiency - Coding, Deployment, Scaling
Drupal Efficiency - Coding, Deployment, ScalingDrupal Efficiency - Coding, Deployment, Scaling
Drupal Efficiency - Coding, Deployment, Scalingsmattoon
 
Drupal Efficiency using open source technologies from Sun
Drupal Efficiency using open source technologies from SunDrupal Efficiency using open source technologies from Sun
Drupal Efficiency using open source technologies from Sunsmattoon
 
Owning computers without shell access 2
Owning computers without shell access 2Owning computers without shell access 2
Owning computers without shell access 2Royce Davis
 
introduction to node.js
introduction to node.jsintroduction to node.js
introduction to node.jsorkaplan
 
Using Puppet in Small Infrastructures
Using Puppet in Small InfrastructuresUsing Puppet in Small Infrastructures
Using Puppet in Small InfrastructuresRachel Andrew
 
The why and how of moving to PHP 5.4/5.5
The why and how of moving to PHP 5.4/5.5The why and how of moving to PHP 5.4/5.5
The why and how of moving to PHP 5.4/5.5Wim Godden
 
Sticky Keys to the Kingdom
Sticky Keys to the KingdomSticky Keys to the Kingdom
Sticky Keys to the KingdomDennis Maldonado
 
Consul administration at scale
Consul administration at scaleConsul administration at scale
Consul administration at scalePierre Souchay
 

Semelhante a Time tested php with libtimemachine (20)

Reutov, yunusov, nagibin random numbers take ii
Reutov, yunusov, nagibin   random numbers take iiReutov, yunusov, nagibin   random numbers take ii
Reutov, yunusov, nagibin random numbers take ii
 
Random numbers
Random numbersRandom numbers
Random numbers
 
How to automate all your SEO projects
How to automate all your SEO projectsHow to automate all your SEO projects
How to automate all your SEO projects
 
php & performance
 php & performance php & performance
php & performance
 
Charla EHU Noviembre 2014 - Desarrollo Web
Charla EHU Noviembre 2014 - Desarrollo WebCharla EHU Noviembre 2014 - Desarrollo Web
Charla EHU Noviembre 2014 - Desarrollo Web
 
PHP & Performance
PHP & PerformancePHP & Performance
PHP & Performance
 
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
 
PHP Sessions and Non-Sessions
PHP Sessions and Non-SessionsPHP Sessions and Non-Sessions
PHP Sessions and Non-Sessions
 
Caching and tuning fun for high scalability
Caching and tuning fun for high scalabilityCaching and tuning fun for high scalability
Caching and tuning fun for high scalability
 
Why and How Powershell will rule the Command Line - Barcamp LA 4
Why and How Powershell will rule the Command Line - Barcamp LA 4Why and How Powershell will rule the Command Line - Barcamp LA 4
Why and How Powershell will rule the Command Line - Barcamp LA 4
 
PowerShell - Be A Cool Blue Kid
PowerShell - Be A Cool Blue KidPowerShell - Be A Cool Blue Kid
PowerShell - Be A Cool Blue Kid
 
Drupal Efficiency - Coding, Deployment, Scaling
Drupal Efficiency - Coding, Deployment, ScalingDrupal Efficiency - Coding, Deployment, Scaling
Drupal Efficiency - Coding, Deployment, Scaling
 
Drupal Efficiency using open source technologies from Sun
Drupal Efficiency using open source technologies from SunDrupal Efficiency using open source technologies from Sun
Drupal Efficiency using open source technologies from Sun
 
Owning computers without shell access 2
Owning computers without shell access 2Owning computers without shell access 2
Owning computers without shell access 2
 
Automate Thyself
Automate ThyselfAutomate Thyself
Automate Thyself
 
introduction to node.js
introduction to node.jsintroduction to node.js
introduction to node.js
 
Using Puppet in Small Infrastructures
Using Puppet in Small InfrastructuresUsing Puppet in Small Infrastructures
Using Puppet in Small Infrastructures
 
The why and how of moving to PHP 5.4/5.5
The why and how of moving to PHP 5.4/5.5The why and how of moving to PHP 5.4/5.5
The why and how of moving to PHP 5.4/5.5
 
Sticky Keys to the Kingdom
Sticky Keys to the KingdomSticky Keys to the Kingdom
Sticky Keys to the Kingdom
 
Consul administration at scale
Consul administration at scaleConsul administration at scale
Consul administration at scale
 

Mais de Nick Galbreath

Making operations visible - devopsdays tokyo 2013
Making operations visible  - devopsdays tokyo 2013Making operations visible  - devopsdays tokyo 2013
Making operations visible - devopsdays tokyo 2013Nick Galbreath
 
Faster Secure Software Development with Continuous Deployment - PH Days 2013
Faster Secure Software Development with Continuous Deployment - PH Days 2013Faster Secure Software Development with Continuous Deployment - PH Days 2013
Faster Secure Software Development with Continuous Deployment - PH Days 2013Nick Galbreath
 
Fixing security by fixing software development
Fixing security by fixing software developmentFixing security by fixing software development
Fixing security by fixing software developmentNick Galbreath
 
DevOpsDays Austin 2013 Reading List
DevOpsDays Austin 2013 Reading ListDevOpsDays Austin 2013 Reading List
DevOpsDays Austin 2013 Reading ListNick Galbreath
 
Care and Feeding of Large Scale Graphite Installations - DevOpsDays Austin 2013
Care and Feeding of Large Scale Graphite Installations - DevOpsDays Austin 2013Care and Feeding of Large Scale Graphite Installations - DevOpsDays Austin 2013
Care and Feeding of Large Scale Graphite Installations - DevOpsDays Austin 2013Nick Galbreath
 
SQL-RISC: New Directions in SQLi Prevention - RSA USA 2013
SQL-RISC: New Directions in SQLi Prevention - RSA USA 2013SQL-RISC: New Directions in SQLi Prevention - RSA USA 2013
SQL-RISC: New Directions in SQLi Prevention - RSA USA 2013Nick Galbreath
 
Rebooting Software Development - OWASP AppSecUSA
Rebooting Software Development - OWASP AppSecUSA Rebooting Software Development - OWASP AppSecUSA
Rebooting Software Development - OWASP AppSecUSA Nick Galbreath
 
libinjection and sqli obfuscation, presented at OWASP NYC
libinjection and sqli obfuscation, presented at OWASP NYClibinjection and sqli obfuscation, presented at OWASP NYC
libinjection and sqli obfuscation, presented at OWASP NYCNick Galbreath
 
Continuous Deployment - The New #1 Security Feature, from BSildesLA 2012
Continuous Deployment - The New #1 Security Feature, from BSildesLA 2012Continuous Deployment - The New #1 Security Feature, from BSildesLA 2012
Continuous Deployment - The New #1 Security Feature, from BSildesLA 2012Nick Galbreath
 
New techniques in sql obfuscation, from DEFCON 20
New techniques in sql obfuscation, from DEFCON 20New techniques in sql obfuscation, from DEFCON 20
New techniques in sql obfuscation, from DEFCON 20Nick Galbreath
 
Data Driven Security, from Gartner Security Summit 2012
Data Driven Security, from Gartner Security Summit 2012Data Driven Security, from Gartner Security Summit 2012
Data Driven Security, from Gartner Security Summit 2012Nick Galbreath
 
Slide show font sampler, black on white
Slide show font sampler, black on whiteSlide show font sampler, black on white
Slide show font sampler, black on whiteNick Galbreath
 
Fraud Engineering, from Merchant Risk Council Annual Meeting 2012
Fraud Engineering, from Merchant Risk Council Annual Meeting 2012Fraud Engineering, from Merchant Risk Council Annual Meeting 2012
Fraud Engineering, from Merchant Risk Council Annual Meeting 2012Nick Galbreath
 
Rate Limiting at Scale, from SANS AppSec Las Vegas 2012
Rate Limiting at Scale, from SANS AppSec Las Vegas 2012Rate Limiting at Scale, from SANS AppSec Las Vegas 2012
Rate Limiting at Scale, from SANS AppSec Las Vegas 2012Nick Galbreath
 
DevOpsSec: Appling DevOps Principles to Security, DevOpsDays Austin 2012
DevOpsSec: Appling DevOps Principles to Security, DevOpsDays Austin 2012DevOpsSec: Appling DevOps Principles to Security, DevOpsDays Austin 2012
DevOpsSec: Appling DevOps Principles to Security, DevOpsDays Austin 2012Nick Galbreath
 

Mais de Nick Galbreath (15)

Making operations visible - devopsdays tokyo 2013
Making operations visible  - devopsdays tokyo 2013Making operations visible  - devopsdays tokyo 2013
Making operations visible - devopsdays tokyo 2013
 
Faster Secure Software Development with Continuous Deployment - PH Days 2013
Faster Secure Software Development with Continuous Deployment - PH Days 2013Faster Secure Software Development with Continuous Deployment - PH Days 2013
Faster Secure Software Development with Continuous Deployment - PH Days 2013
 
Fixing security by fixing software development
Fixing security by fixing software developmentFixing security by fixing software development
Fixing security by fixing software development
 
DevOpsDays Austin 2013 Reading List
DevOpsDays Austin 2013 Reading ListDevOpsDays Austin 2013 Reading List
DevOpsDays Austin 2013 Reading List
 
Care and Feeding of Large Scale Graphite Installations - DevOpsDays Austin 2013
Care and Feeding of Large Scale Graphite Installations - DevOpsDays Austin 2013Care and Feeding of Large Scale Graphite Installations - DevOpsDays Austin 2013
Care and Feeding of Large Scale Graphite Installations - DevOpsDays Austin 2013
 
SQL-RISC: New Directions in SQLi Prevention - RSA USA 2013
SQL-RISC: New Directions in SQLi Prevention - RSA USA 2013SQL-RISC: New Directions in SQLi Prevention - RSA USA 2013
SQL-RISC: New Directions in SQLi Prevention - RSA USA 2013
 
Rebooting Software Development - OWASP AppSecUSA
Rebooting Software Development - OWASP AppSecUSA Rebooting Software Development - OWASP AppSecUSA
Rebooting Software Development - OWASP AppSecUSA
 
libinjection and sqli obfuscation, presented at OWASP NYC
libinjection and sqli obfuscation, presented at OWASP NYClibinjection and sqli obfuscation, presented at OWASP NYC
libinjection and sqli obfuscation, presented at OWASP NYC
 
Continuous Deployment - The New #1 Security Feature, from BSildesLA 2012
Continuous Deployment - The New #1 Security Feature, from BSildesLA 2012Continuous Deployment - The New #1 Security Feature, from BSildesLA 2012
Continuous Deployment - The New #1 Security Feature, from BSildesLA 2012
 
New techniques in sql obfuscation, from DEFCON 20
New techniques in sql obfuscation, from DEFCON 20New techniques in sql obfuscation, from DEFCON 20
New techniques in sql obfuscation, from DEFCON 20
 
Data Driven Security, from Gartner Security Summit 2012
Data Driven Security, from Gartner Security Summit 2012Data Driven Security, from Gartner Security Summit 2012
Data Driven Security, from Gartner Security Summit 2012
 
Slide show font sampler, black on white
Slide show font sampler, black on whiteSlide show font sampler, black on white
Slide show font sampler, black on white
 
Fraud Engineering, from Merchant Risk Council Annual Meeting 2012
Fraud Engineering, from Merchant Risk Council Annual Meeting 2012Fraud Engineering, from Merchant Risk Council Annual Meeting 2012
Fraud Engineering, from Merchant Risk Council Annual Meeting 2012
 
Rate Limiting at Scale, from SANS AppSec Las Vegas 2012
Rate Limiting at Scale, from SANS AppSec Las Vegas 2012Rate Limiting at Scale, from SANS AppSec Las Vegas 2012
Rate Limiting at Scale, from SANS AppSec Las Vegas 2012
 
DevOpsSec: Appling DevOps Principles to Security, DevOpsDays Austin 2012
DevOpsSec: Appling DevOps Principles to Security, DevOpsDays Austin 2012DevOpsSec: Appling DevOps Principles to Security, DevOpsDays Austin 2012
DevOpsSec: Appling DevOps Principles to Security, DevOpsDays Austin 2012
 

Último

Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024TopCSSGallery
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Nikki Chapple
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Farhan Tariq
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observabilityitnewsafrica
 

Último (20)

Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
 

Time tested php with libtimemachine

  • 1. Time Tested PHP Advanced testing techniques with libTimeMachine Nick Galbreath nickg@client9.com @ngalbreath Vince Tse vtonehundred@gmail.com @vtonehundred 2012-07-19
  • 2. Follow along or get the latest version at: http://slidesha.re/ NDc5mK
  • 3. Time Happens While it should be avoided as much as possible, sometimes "time happens" and applications need testing based on simulated time. • Financial applications (e.g. simulating ad spending and budgeting) • Security features (what happens when the cookie or auth token expires?) • System testing (what happens on leap year? day light savings time? 2038?) • Anything that runs periodically ("on the hour")
  • 4. PHP Time Sources • $_SERVER['REQUEST_TIME'] • time() • microtime() • gettimeofday() • Single argument of date(fmt) (equivalent to date(fmt, time())
  • 5. Using $_SERVER['REQUEST_TIME'] • Available in all SAPI contexts (mod_php, CLI, CGI, FPM...) • Created once at time of request • "Lowest Cost" -- array lookup • Easy to spoof in unit tests • Can't spoof for functional tests • Can't use it for timing
  • 6. Passing as Argument • Don't call time() et al directly in a function but instead pass current time in. • Allows unit testing • Follows dependency injection best-practice
  • 7. But what if your code isn't or can't be structured that way?
  • 8. Time Travel with libtimemachine! https://github.com/vtonehundred/libtimemachine Changes the system calls that PHP uses to get the current time • time (defined in <time.h>) • gettimeofday (defined in <sys/time.h>) • clock_gettime (defined in <time.h>) and allows you to change them backwards or forward, relative or absolute.
  • 9. LibTimeMachine • Use some secret loader sexiness to change the underlying system calls. (see 'man ld-linux' for details) • Works on Linux systems • Works on Mac OS X (only tested on 10.7.4) • Sorry Windows • (not sure about FreeBSD)
  • 10. Plug and Play git clone git://github.com/vtonehundred/libtimemachine.git cd libtimemachine make sudo cp libtimemachine.so [ /lib64 or /lib ] sudo ldconfig
  • 11. To use! • libtimemachine reads /tmp/libtimemachine.conf (or whatever file you want using the LIBTIMEMACHINE_CONF environment variable) • Single number controls how to adjust time • If starts with "-" or "+" then current time will be adjusted by a relative amount. • If "just numbers" then the time is fixed with this value • If "0" or missing, then use current time
  • 12. PHP CLI Just add LD_PRELOAD=libtimemachine.so before php on the command line $ php -r 'echo date("rn");' Mon, 28 May 2012 23:03:38 -0400 $ # go back one year $ echo "-31536000" > /tmp/libtimemachine.conf $ LD_PRELOAD=libtimemachine.so php -r 'echo date("rn");' Sun, 29 May 2011 23:03:49 -0400 $ #winning
  • 13. PHP 5.4 Built-In WebServer This is the easiest way to go! $ date Mon May 28 23:27:19 2012 $ echo "31536000" > /tmp/libtimemachine.conf $ LD_PRELOAD=/lib64/libtimemachine.so ./php -t ~/root -S 127.0.0.1:80 PHP 5.4.3 Development Server started at Tue May 28 23:29:19 2013 Listening on 127.0.0.1:80 Document root is ~/root Press Ctrl-C to quit. [Tue May 28 23:29:22 2013] 127.0.0.1:34913 [200]: ~/time.php Command line CGI works similarly
  • 14. Apache mod_php Debian / Ubuntu • Install libtimemachine.so in /lib64 or / lib depending on your OS. • (for good measure also do "sudo ldconfig") • /etc/apache2/envvars controls the apache and workers environment. Add export LD_PRELOAD=libtimemachine.so • sudo /etc/init.d/apache2 restart
  • 15. <?php header('Content-Type: text/plain'); date_default_timezone_set('UTC'); //if you need it printf("REQUEST_TIME : %sn", date("r",$_SERVER['REQUEST_TIME'])); printf("time() : %sn", date("r", time())); printf("microtime() : %sn", date("r", microtime(TRUE))); printf("date('r') : %sn", date("r")); printf("gettimeofday() : %sn", date("r", gettimeofday(TRUE))); //print_r($_SERVER);
  • 16. Back One Day! $ date Sun, 27 May 2012 19:35:41 +0000 $ echo "-86400" > /tmp/libtimemachine.conf $ curl 'http://127.0.0.1/phptime.php' REQUEST_TIME : Sat, 26 May 2012 19:35:54 +0000 time() : Sat, 26 May 2012 19:35:54 +0000 microtime() : Sat, 26 May 2012 19:35:54 +0000 date('r') : Sat, 26 May 2012 19:35:54 +0000 gettimeofday() : Sat, 26 May 2012 19:35:54 +0000
  • 17. apache mod_php RedHat/CentOS • Disable SELinux: in /etc/selinux/config set SELINUX=disabled • put libtimemachine.so in /lib64 or /lib depending on your OS. • (for good measure also do "sudo ldconfig") • add to /etc/sysconfig/httpd export LD_PRELOAD=libtimemachine.so • And then...
  • 18. Fail on Apache + mod_php + CentOS 6.2 • SELinux removes LD_PRELOAD • Even though we disabled SELinux, it appears the linker isn't getting LD_PRELOAD • mod_php is an shared library that loads shared libraries. hmmm • I suspect a bug in the OS? Or maybe mod_php is compiled differently. • Use PHP 5.4's built-in web server instead for testing.
  • 19. Future Work • Apache + PHP CGI (does anyone do this?) • nginx + PHP FPM (the new hotness) • Figuring out what is going on with CentOS • Testing on mysql server. • Packaging
  • 20. Detecting libtimemachine • Look for existence of /tmp/libtimemachine.conf • Shell out and use "date +%s" and compare to time() • Use Apache mod_env and add PassEnv LD_PRELOAD to let PHP see the environment variable
  • 21. Evil • Can this technique be used for evil? • Oh yeah. • type "LD_PRELOAD rootkit" in your favorite search engine for details
  • 22. Mac OS X Notes • Only tested on 10.7.4 • Mac OS X uses dyld for linking and works different than gnu ld. See 'man dyld' for details. • Instead of LD_PRELOAD, use: DYLD_INSERT_LIBRARIES=./libtimemachine.dylib • If that doesn't work, add DYLD_FORCE_FLAT_NAMESPACE=1
  • 23. Gotchas • if you globally set LD_PRELOAD, export LD_PRELOAD=libtimemachine.so then everything you do might be time shifted (to undo 'unset LD_PRELOAD') • Your application might run a bit slower since every time lookup requires reading /tmp/libtimemachine.conf
  • 24. Thanks! https://github.com/vtonehundred/libtimemachine Nick Galbreath nickg@client9.com @ngalbreath Vince Tse vtonehundred@gmail.com @vtonehundred

Notas do Editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n